711697655a7ee2a2e02934e78cd7b9e38b170164
[dragonfly.git] / sys / dev / serial / rp / rp.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (c) Comtrol Corporation <support@comtrol.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted prodived that the follwoing conditions
9  * are met.
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notive, this list of conditions and the following disclainer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials prodided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *       This product includes software developed by Comtrol Corporation.
18  * 4. The name of Comtrol Corporation may not be used to endorse or 
19  *    promote products derived from this software without specific 
20  *    prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
26  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD: src/sys/dev/rp/rp.c,v 1.45.2.2 2002/11/07 22:26:59 tegge Exp $
35  */
36
37 /* 
38  * rp.c - for RocketPort FreeBSD
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/fcntl.h>
44 #include <sys/malloc.h>
45 #include <sys/tty.h>
46 #include <sys/proc.h>
47 #include <sys/priv.h>
48 #include <sys/dkstat.h>
49 #include <sys/conf.h>
50 #include <sys/kernel.h>
51 #include <sys/bus.h>
52 #include <sys/rman.h>
53 #include <sys/thread2.h>
54
55 #define ROCKET_C
56 #include "rpreg.h"
57 #include "rpvar.h"
58
59 static const char RocketPortVersion[] = "3.02";
60
61 static Byte_t RData[RDATASIZE] =
62 {
63    0x00, 0x09, 0xf6, 0x82,
64    0x02, 0x09, 0x86, 0xfb,
65    0x04, 0x09, 0x00, 0x0a,
66    0x06, 0x09, 0x01, 0x0a,
67    0x08, 0x09, 0x8a, 0x13,
68    0x0a, 0x09, 0xc5, 0x11,
69    0x0c, 0x09, 0x86, 0x85,
70    0x0e, 0x09, 0x20, 0x0a,
71    0x10, 0x09, 0x21, 0x0a,
72    0x12, 0x09, 0x41, 0xff,
73    0x14, 0x09, 0x82, 0x00,
74    0x16, 0x09, 0x82, 0x7b,
75    0x18, 0x09, 0x8a, 0x7d,
76    0x1a, 0x09, 0x88, 0x81,
77    0x1c, 0x09, 0x86, 0x7a,
78    0x1e, 0x09, 0x84, 0x81,
79    0x20, 0x09, 0x82, 0x7c,
80    0x22, 0x09, 0x0a, 0x0a
81 };
82
83 static Byte_t RRegData[RREGDATASIZE]=
84 {
85    0x00, 0x09, 0xf6, 0x82,             /* 00: Stop Rx processor */
86    0x08, 0x09, 0x8a, 0x13,             /* 04: Tx software flow control */
87    0x0a, 0x09, 0xc5, 0x11,             /* 08: XON char */
88    0x0c, 0x09, 0x86, 0x85,             /* 0c: XANY */
89    0x12, 0x09, 0x41, 0xff,             /* 10: Rx mask char */
90    0x14, 0x09, 0x82, 0x00,             /* 14: Compare/Ignore #0 */
91    0x16, 0x09, 0x82, 0x7b,             /* 18: Compare #1 */
92    0x18, 0x09, 0x8a, 0x7d,             /* 1c: Compare #2 */
93    0x1a, 0x09, 0x88, 0x81,             /* 20: Interrupt #1 */
94    0x1c, 0x09, 0x86, 0x7a,             /* 24: Ignore/Replace #1 */
95    0x1e, 0x09, 0x84, 0x81,             /* 28: Interrupt #2 */
96    0x20, 0x09, 0x82, 0x7c,             /* 2c: Ignore/Replace #2 */
97    0x22, 0x09, 0x0a, 0x0a              /* 30: Rx FIFO Enable */
98 };
99
100 #if 0
101 /* IRQ number to MUDBAC register 2 mapping */
102 Byte_t sIRQMap[16] =
103 {
104    0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
105 };
106 #endif
107
108 Byte_t rp_sBitMapClrTbl[8] =
109 {
110    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
111 };
112
113 Byte_t rp_sBitMapSetTbl[8] =
114 {
115    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
116 };
117
118 /* Actually not used */
119 #if 0 /* notdef */
120 struct termios deftermios = {
121         TTYDEF_IFLAG,
122         TTYDEF_OFLAG,
123         TTYDEF_CFLAG,
124         TTYDEF_LFLAG,
125         { CEOF, CEOL, CEOL, CERASE, CWERASE, CKILL, CREPRINT,
126         _POSIX_VDISABLE, CINTR, CQUIT, CSUSP, CDSUSP, CSTART, CSTOP, CLNEXT,
127         CDISCARD, CMIN, CTIME, CSTATUS, _POSIX_VDISABLE },
128         TTYDEF_SPEED,
129         TTYDEF_SPEED
130 };
131 #endif
132
133 /***************************************************************************
134 Function: sReadAiopID
135 Purpose:  Read the AIOP idenfication number directly from an AIOP.
136 Call:     sReadAiopID(CtlP, aiop)
137           CONTROLLER_T *CtlP; Ptr to controller structure
138           int aiop: AIOP index
139 Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
140                  is replace by an identifying number.
141           Flag AIOPID_NULL if no valid AIOP is found
142 Warnings: No context switches are allowed while executing this function.
143
144 */
145 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
146 {
147    Byte_t AiopID;               /* ID byte from AIOP */
148
149    crit_enter();
150    rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL);     /* reset AIOP */
151    rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
152    AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
153    crit_exit();
154    if(AiopID == 0x06)
155       return(1);
156    else                                /* AIOP does not exist */
157       return(-1);
158 }
159
160 /***************************************************************************
161 Function: sReadAiopNumChan
162 Purpose:  Read the number of channels available in an AIOP directly from
163           an AIOP.
164 Call:     sReadAiopNumChan(CtlP, aiop)
165           CONTROLLER_T *CtlP; Ptr to controller structure
166           int aiop: AIOP index
167 Return:   int: The number of channels available
168 Comments: The number of channels is determined by write/reads from identical
169           offsets within the SRAM address spaces for channels 0 and 4.
170           If the channel 4 space is mirrored to channel 0 it is a 4 channel
171           AIOP, otherwise it is an 8 channel.
172 Warnings: No context switches are allowed while executing this function.
173 */
174 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
175 {
176    Word_t x, y;
177
178    crit_enter();
179    rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
180    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0);        /* read from SRAM, chan 0 */
181    x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
182    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
183    y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
184    crit_exit();
185    if(x != y)  /* if different must be 8 chan */
186       return(8);
187    else
188       return(4);
189 }
190
191 /***************************************************************************
192 Function: sInitChan
193 Purpose:  Initialization of a channel and channel structure
194 Call:     sInitChan(CtlP,ChP,AiopNum,ChanNum)
195           CONTROLLER_T *CtlP; Ptr to controller structure
196           CHANNEL_T *ChP; Ptr to channel structure
197           int AiopNum; AIOP number within controller
198           int ChanNum; Channel number within AIOP
199 Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
200                number exceeds number of channels available in AIOP.
201 Comments: This function must be called before a channel can be used.
202 Warnings: No range checking on any of the parameters is done.
203
204           No context switches are allowed while executing this function.
205 */
206 int sInitChan(  CONTROLLER_T *CtlP,
207                 CHANNEL_T *ChP,
208                 int AiopNum,
209                 int ChanNum)
210 {
211    int i, ChOff;
212    Byte_t *ChR;
213    static Byte_t R[4];
214
215    if(ChanNum >= CtlP->AiopNumChan[AiopNum])
216       return(FALSE);                   /* exceeds num chans in AIOP */
217
218    crit_enter();
219    /* Channel, AIOP, and controller identifiers */
220    ChP->CtlP = CtlP;
221    ChP->ChanID = CtlP->AiopID[AiopNum];
222    ChP->AiopNum = AiopNum;
223    ChP->ChanNum = ChanNum;
224
225    /* Initialize the channel from the RData array */
226    for(i=0; i < RDATASIZE; i+=4)
227    {
228       R[0] = RData[i];
229       R[1] = RData[i+1] + 0x10 * ChanNum;
230       R[2] = RData[i+2];
231       R[3] = RData[i+3];
232       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)&R[0]));
233    }
234
235    ChR = ChP->R;
236    for(i=0; i < RREGDATASIZE; i+=4)
237    {
238       ChR[i] = RRegData[i];
239       ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
240       ChR[i+2] = RRegData[i+2];
241       ChR[i+3] = RRegData[i+3];
242    }
243
244    /* Indexed registers */
245    ChOff = (Word_t)ChanNum * 0x1000;
246
247    ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
248    ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
249    ChP->BaudDiv[2] = (Byte_t)BRD9600;
250    ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
251    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->BaudDiv[0]);
252
253    ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
254    ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
255    ChP->TxControl[2] = 0;
256    ChP->TxControl[3] = 0;
257    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
258
259    ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
260    ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
261    ChP->RxControl[2] = 0;
262    ChP->RxControl[3] = 0;
263    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
264
265    ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
266    ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
267    ChP->TxEnables[2] = 0;
268    ChP->TxEnables[3] = 0;
269    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxEnables[0]);
270
271    ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
272    ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
273    ChP->TxCompare[2] = 0;
274    ChP->TxCompare[3] = 0;
275    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxCompare[0]);
276
277    ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
278    ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
279    ChP->TxReplace1[2] = 0;
280    ChP->TxReplace1[3] = 0;
281    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace1[0]);
282
283    ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
284    ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
285    ChP->TxReplace2[2] = 0;
286    ChP->TxReplace2[3] = 0;
287    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace2[0]);
288
289    ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
290    ChP->TxFIFO = ChOff + _TX_FIFO;
291
292    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
293    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
294    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
295    rp_writech2(ChP,_INDX_DATA,0);
296    ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
297    ChP->RxFIFO = ChOff + _RX_FIFO;
298
299    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
300    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
301    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
302    rp_writech2(ChP,_INDX_DATA,0);
303    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
304    rp_writech2(ChP,_INDX_DATA,0);
305    ChP->TxPrioCnt = ChOff + _TXP_CNT;
306    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
307    rp_writech1(ChP,_INDX_DATA,0);
308    ChP->TxPrioPtr = ChOff + _TXP_PNTR;
309    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
310    rp_writech1(ChP,_INDX_DATA,0);
311    ChP->TxPrioBuf = ChOff + _TXP_BUF;
312    sEnRxProcessor(ChP);                /* start the Rx processor */
313
314    crit_exit();
315    return(TRUE);
316 }
317
318 /***************************************************************************
319 Function: sStopRxProcessor
320 Purpose:  Stop the receive processor from processing a channel.
321 Call:     sStopRxProcessor(ChP)
322           CHANNEL_T *ChP; Ptr to channel structure
323
324 Comments: The receive processor can be started again with sStartRxProcessor().
325           This function causes the receive processor to skip over the
326           stopped channel.  It does not stop it from processing other channels.
327
328 Warnings: No context switches are allowed while executing this function.
329
330           Do not leave the receive processor stopped for more than one
331           character time.
332
333           After calling this function a delay of 4 uS is required to ensure
334           that the receive processor is no longer processing this channel.
335 */
336 void sStopRxProcessor(CHANNEL_T *ChP)
337 {
338    Byte_t R[4];
339
340    crit_enter();
341    R[0] = ChP->R[0];
342    R[1] = ChP->R[1];
343    R[2] = 0x0a;
344    R[3] = ChP->R[3];
345    rp_writech4(ChP, _INDX_ADDR,*(DWord_t *)&R[0]);
346    crit_exit();
347 }
348
349 /***************************************************************************
350 Function: sFlushRxFIFO
351 Purpose:  Flush the Rx FIFO
352 Call:     sFlushRxFIFO(ChP)
353           CHANNEL_T *ChP; Ptr to channel structure
354 Return:   void
355 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
356           while it is being flushed the receive processor is stopped
357           and the transmitter is disabled.  After these operations a
358           4 uS delay is done before clearing the pointers to allow
359           the receive processor to stop.  These items are handled inside
360           this function.
361 Warnings: No context switches are allowed while executing this function.
362 */
363 void sFlushRxFIFO(CHANNEL_T *ChP)
364 {
365    int i;
366    Byte_t Ch;                   /* channel number within AIOP */
367    int RxFIFOEnabled;                  /* TRUE if Rx FIFO enabled */
368
369    if(sGetRxCnt(ChP) == 0)             /* Rx FIFO empty */
370       return;                          /* don't need to flush */
371
372    crit_enter();
373    RxFIFOEnabled = FALSE;
374    if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
375    {
376       RxFIFOEnabled = TRUE;
377       sDisRxFIFO(ChP);                 /* disable it */
378       for(i=0; i < 2000/200; i++)       /* delay 2 uS to allow proc to disable FIFO*/
379          rp_readch1(ChP,_INT_CHAN);             /* depends on bus i/o timing */
380    }
381    sGetChanStatus(ChP);          /* clear any pending Rx errors in chan stat */
382    Ch = (Byte_t)sGetChanNum(ChP);
383    rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
384    rp_writech1(ChP,_CMD_REG,Ch);                       /* remove reset Rx FIFO count */
385    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
386    rp_writech2(ChP,_INDX_DATA,0);
387    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
388    rp_writech2(ChP,_INDX_DATA,0);
389    if(RxFIFOEnabled)
390       sEnRxFIFO(ChP);                  /* enable Rx FIFO */
391    crit_exit();
392 }
393
394 /***************************************************************************
395 Function: sFlushTxFIFO
396 Purpose:  Flush the Tx FIFO
397 Call:     sFlushTxFIFO(ChP)
398           CHANNEL_T *ChP; Ptr to channel structure
399 Return:   void
400 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
401           while it is being flushed the receive processor is stopped
402           and the transmitter is disabled.  After these operations a
403           4 uS delay is done before clearing the pointers to allow
404           the receive processor to stop.  These items are handled inside
405           this function.
406 Warnings: No context switches are allowed while executing this function.
407 */
408 void sFlushTxFIFO(CHANNEL_T *ChP)
409 {
410    int i;
411    Byte_t Ch;                   /* channel number within AIOP */
412    int TxEnabled;                      /* TRUE if transmitter enabled */
413
414    crit_enter();
415    if(sGetTxCnt(ChP) == 0) {           /* Tx FIFO empty */
416       crit_exit();
417       return;                          /* don't need to flush */
418    }
419
420    TxEnabled = FALSE;
421    if(ChP->TxControl[3] & TX_ENABLE)
422    {
423       TxEnabled = TRUE;
424       sDisTransmit(ChP);               /* disable transmitter */
425    }
426    sStopRxProcessor(ChP);              /* stop Rx processor */
427    for(i = 0; i < 4000/200; i++)         /* delay 4 uS to allow proc to stop */
428       rp_readch1(ChP,_INT_CHAN);        /* depends on bus i/o timing */
429    Ch = (Byte_t)sGetChanNum(ChP);
430    rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT);     /* apply reset Tx FIFO count */
431    rp_writech1(ChP,_CMD_REG,Ch);                       /* remove reset Tx FIFO count */
432    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
433    rp_writech2(ChP,_INDX_DATA,0);
434    if(TxEnabled)
435       sEnTransmit(ChP);                /* enable transmitter */
436    sStartRxProcessor(ChP);             /* restart Rx processor */
437    crit_exit();
438 }
439
440 /***************************************************************************
441 Function: sWriteTxPrioByte
442 Purpose:  Write a byte of priority transmit data to a channel
443 Call:     sWriteTxPrioByte(ChP,Data)
444           CHANNEL_T *ChP; Ptr to channel structure
445           Byte_t Data; The transmit data byte
446
447 Return:   int: 1 if the bytes is successfully written, otherwise 0.
448
449 Comments: The priority byte is transmitted before any data in the Tx FIFO.
450
451 Warnings: No context switches are allowed while executing this function.
452 */
453 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
454 {
455    Byte_t DWBuf[4];             /* buffer for double word writes */
456    Word_t *WordPtr;          /* must be far because Win SS != DS */
457
458    crit_enter();
459    if(sGetTxCnt(ChP) > 1)              /* write it to Tx priority buffer */
460    {
461       rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
462       if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) {/* priority buffer busy */
463          crit_exit();
464          return(0);                    /* nothing sent */
465       }
466
467       WordPtr = (Word_t *)(&DWBuf[0]);
468       *WordPtr = ChP->TxPrioBuf;       /* data byte address */
469
470       DWBuf[2] = Data;                 /* data byte value */
471       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
472
473       *WordPtr = ChP->TxPrioCnt;       /* Tx priority count address */
474
475       DWBuf[2] = PRI_PEND + 1;         /* indicate 1 byte pending */
476       DWBuf[3] = 0;                    /* priority buffer pointer */
477       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
478    }
479    else                                /* write it to Tx FIFO */
480    {
481       sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
482    }
483    crit_exit();
484    return(1);                          /* 1 byte sent */
485 }
486
487 /***************************************************************************
488 Function: sEnInterrupts
489 Purpose:  Enable one or more interrupts for a channel
490 Call:     sEnInterrupts(ChP,Flags)
491           CHANNEL_T *ChP; Ptr to channel structure
492           Word_t Flags: Interrupt enable flags, can be any combination
493              of the following flags:
494                 TXINT_EN:   Interrupt on Tx FIFO empty
495                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
496                             sSetRxTrigger())
497                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
498                 MCINT_EN:   Interrupt on modem input change
499                 CHANINT_EN: Allow channel interrupt signal to the AIOP's
500                             Interrupt Channel Register.
501 Return:   void
502 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
503           enabled.  If an interrupt enable flag is not set in Flags, that
504           interrupt will not be changed.  Interrupts can be disabled with
505           function sDisInterrupts().
506
507           This function sets the appropriate bit for the channel in the AIOP's
508           Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
509           this channel's bit to be set in the AIOP's Interrupt Channel Register.
510
511           Interrupts must also be globally enabled before channel interrupts
512           will be passed on to the host.  This is done with function
513           sEnGlobalInt().
514
515           In some cases it may be desirable to disable interrupts globally but
516           enable channel interrupts.  This would allow the global interrupt
517           status register to be used to determine which AIOPs need service.
518 */
519 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
520 {
521    Byte_t Mask;                 /* Interrupt Mask Register */
522
523    ChP->RxControl[2] |=
524       ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
525
526    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
527
528    ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
529
530    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
531
532    if(Flags & CHANINT_EN)
533    {
534       Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
535       rp_writech1(ChP,_INT_MASK,Mask);
536    }
537 }
538
539 /***************************************************************************
540 Function: sDisInterrupts
541 Purpose:  Disable one or more interrupts for a channel
542 Call:     sDisInterrupts(ChP,Flags)
543           CHANNEL_T *ChP; Ptr to channel structure
544           Word_t Flags: Interrupt flags, can be any combination
545              of the following flags:
546                 TXINT_EN:   Interrupt on Tx FIFO empty
547                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
548                             sSetRxTrigger())
549                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
550                 MCINT_EN:   Interrupt on modem input change
551                 CHANINT_EN: Disable channel interrupt signal to the
552                             AIOP's Interrupt Channel Register.
553 Return:   void
554 Comments: If an interrupt flag is set in Flags, that interrupt will be
555           disabled.  If an interrupt flag is not set in Flags, that
556           interrupt will not be changed.  Interrupts can be enabled with
557           function sEnInterrupts().
558
559           This function clears the appropriate bit for the channel in the AIOP's
560           Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
561           this channel's bit from being set in the AIOP's Interrupt Channel
562           Register.
563 */
564 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
565 {
566    Byte_t Mask;                 /* Interrupt Mask Register */
567
568    ChP->RxControl[2] &=
569          ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
570    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
571    ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
572    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
573
574    if(Flags & CHANINT_EN)
575    {
576       Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
577       rp_writech1(ChP,_INT_MASK,Mask);
578    }
579 }
580
581 /*********************************************************************
582   Begin FreeBsd-specific driver code
583 **********************************************************************/
584
585 static timeout_t rpdtrwakeup;
586
587 static  d_open_t        rpopen;
588 static  d_close_t       rpclose;
589 static  d_write_t       rpwrite;
590 static  d_ioctl_t       rpioctl;
591
592 static struct dev_ops rp_ops = {
593         { "rp", 0, D_TTY },
594         .d_open =       rpopen,
595         .d_close =      rpclose,
596         .d_read =       ttyread,
597         .d_write =      rpwrite,
598         .d_ioctl =      rpioctl,
599         .d_kqfilter =   ttykqfilter,
600         .d_revoke =     ttyrevoke
601 };
602
603 static int      rp_num_ports_open = 0;
604 static int      rp_ndevs = 0;
605 static int      minor_to_unit[128];
606 static int      rp_initialized;
607 static struct callout rp_poll_ch;
608
609 static int rp_num_ports[4];     /* Number of ports on each controller */
610
611 #define POLL_INTERVAL 1
612
613 #define CALLOUT_MASK            0x80
614 #define CONTROL_MASK            0x60
615 #define CONTROL_INIT_STATE      0x20
616 #define CONTROL_LOCK_STATE      0x40
617 #define DEV_UNIT(dev)   (MINOR_TO_UNIT(minor(dev))
618 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
619 #define MINOR_MAGIC(dev)        ((minor(dev)) & ~MINOR_MAGIC_MASK)
620 #define IS_CALLOUT(dev)         (minor(dev) & CALLOUT_MASK)
621 #define IS_CONTROL(dev)         (minor(dev) & CONTROL_MASK)
622
623 #define RP_ISMULTIPORT(dev)     ((dev)->id_flags & 0x1)
624 #define RP_MPMASTER(dev)        (((dev)->id_flags >> 8) & 0xff)
625 #define RP_NOTAST4(dev)         ((dev)->id_flags & 0x04)
626
627 static  struct  rp_port *p_rp_addr[4];
628 static  struct  rp_port *p_rp_table[MAX_RP_PORTS];
629 #define rp_addr(unit)   (p_rp_addr[unit])
630 #define rp_table(port)  (p_rp_table[port])
631
632 /*
633  * The top-level routines begin here
634  */
635
636 static  int     rpparam (struct tty *, struct termios *);
637 static  void    rpstart (struct tty *);
638 static  void    rpstop (struct tty *, int);
639 static  void    rphardclose     (struct rp_port *);
640 static  void    rp_disc_optim   (struct tty *tp, struct termios *t);
641
642 /*
643  * NOTE: Must be called with tty_token held
644  */
645 static void
646 rp_do_receive(struct rp_port *rp, struct tty *tp,
647                         CHANNEL_t *cp, unsigned int ChanStatus)
648 {
649         unsigned        int     CharNStat;
650         int     ToRecv, wRecv, ch, ttynocopy;
651
652         ASSERT_LWKT_TOKEN_HELD(&tty_token);
653         ToRecv = sGetRxCnt(cp);
654         if(ToRecv == 0)
655                 return;
656
657 /*      If status indicates there are errored characters in the
658         FIFO, then enter status mode (a word in FIFO holds
659         characters and status)
660 */
661
662         if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
663                 if(!(ChanStatus & STATMODE)) {
664                         ChanStatus |= STATMODE;
665                         sEnRxStatusMode(cp);
666                 }
667         }
668 /*
669         if we previously entered status mode then read down the
670         FIFO one word at a time, pulling apart the character and
671         the status. Update error counters depending on status.
672 */
673         if(ChanStatus & STATMODE) {
674                 while(ToRecv) {
675                         if(tp->t_state & TS_TBLOCK) {
676                                 break;
677                         }
678                         CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
679                         ch = CharNStat & 0xff;
680
681                         if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
682                                 ch |= TTY_FE;
683                         else if (CharNStat & STMPARITYH)
684                                 ch |= TTY_PE;
685                         else if (CharNStat & STMRCVROVRH)
686                                 rp->rp_overflows++;
687
688                         (*linesw[tp->t_line].l_rint)(ch, tp);
689                         ToRecv--;
690                 }
691 /*
692         After emtying FIFO in status mode, turn off status mode
693 */
694
695                 if(sGetRxCnt(cp) == 0) {
696                         sDisRxStatusMode(cp);
697                 }
698         } else {
699                 /*
700                  * Avoid the grotesquely inefficient lineswitch routine
701                  * (ttyinput) in "raw" mode.  It usually takes about 450
702                  * instructions (that's without canonical processing or echo!).
703                  * slinput is reasonably fast (usually 40 instructions plus
704                  * call overhead).
705                  */
706                 ToRecv = sGetRxCnt(cp);
707                 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
708                         if ( ToRecv > RXFIFO_SIZE ) {
709                                 ToRecv = RXFIFO_SIZE;
710                         }
711                         wRecv = ToRecv >> 1;
712                         if ( wRecv ) {
713                                 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
714                         }
715                         if ( ToRecv & 1 ) {
716                                 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
717                         }
718                         tk_nin += ToRecv;
719                         tk_rawcc += ToRecv;
720                         tp->t_rawcc += ToRecv;
721                         ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
722                         ttwakeup(tp);
723                 } else {
724                         while (ToRecv) {
725                                 if(tp->t_state & TS_TBLOCK) {
726                                         break;
727                                 }
728                                 ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
729                                 crit_enter();
730                                 (*linesw[tp->t_line].l_rint)(ch, tp);
731                                 crit_exit();
732                                 ToRecv--;
733                         }
734                 }
735         }
736 }
737
738 /*
739  * NOTE: Must be called with tty_token held
740  */
741 static void
742 rp_handle_port(struct rp_port *rp)
743 {
744         CHANNEL_t       *cp;
745         struct  tty     *tp;
746         unsigned        int     IntMask, ChanStatus;
747
748         ASSERT_LWKT_TOKEN_HELD(&tty_token);
749
750         if(!rp)
751                 return;
752
753         cp = &rp->rp_channel;
754         tp = rp->rp_tty;
755         IntMask = sGetChanIntID(cp);
756         IntMask = IntMask & rp->rp_intmask;
757         ChanStatus = sGetChanStatus(cp);
758         if(IntMask & RXF_TRIG)
759                 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
760                         rp_do_receive(rp, tp, cp, ChanStatus);
761                 }
762         if(IntMask & DELTA_CD) {
763                 if(ChanStatus & CD_ACT) {
764                         if(!(tp->t_state & TS_CARR_ON) ) {
765                                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
766                         }
767                 } else {
768                         if((tp->t_state & TS_CARR_ON)) {
769                                 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
770                                 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
771                                         rphardclose(rp);
772                                 }
773                         }
774                 }
775         }
776 /*      oldcts = rp->rp_cts;
777         rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
778         if(oldcts != rp->rp_cts) {
779                 kprintf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
780         }
781 */
782 }
783
784 static void rp_do_poll(void *not_used)
785 {
786         CONTROLLER_t    *ctl;
787         struct rp_port  *rp;
788         struct tty      *tp;
789         int     unit, aiop, ch, line, count;
790         unsigned char   CtlMask, AiopMask;
791
792         lwkt_gettoken(&tty_token);
793         for(unit = 0; unit < rp_ndevs; unit++) {
794         rp = rp_addr(unit);
795         ctl = rp->rp_ctlp;
796         CtlMask = ctl->ctlmask(ctl);
797         for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
798                 if(CtlMask & 1) {
799                         AiopMask = sGetAiopIntStatus(ctl, aiop);
800                         for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
801                                 if(AiopMask & 1) {
802                                         line = (unit << 5) | (aiop << 3) | ch;
803                                         rp = rp_table(line);
804                                         rp_handle_port(rp);
805                                 }
806                         }
807                 }
808         }
809
810         for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
811                         line++, rp++) {
812                 tp = rp->rp_tty;
813                 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
814                         count = sGetTxCnt(&rp->rp_channel);
815                         if(count == 0)
816                                 tp->t_state &= ~(TS_BUSY);
817                         if(!(tp->t_state & TS_TTSTOP) &&
818                                 (count <= rp->rp_restart)) {
819                                 (*linesw[tp->t_line].l_start)(tp);
820                         }
821                 }
822         }
823         }
824         if(rp_num_ports_open)
825                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
826         lwkt_reltoken(&tty_token);
827 }
828
829 int
830 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
831 {
832         int     unit;
833         int     num_chan;
834         int     aiop, chan, port;
835         int     ChanStatus, line, i, count;
836         int     retval;
837         struct  rp_port *rp;
838         struct  tty     *tty;
839
840         lwkt_gettoken(&tty_token);
841         unit = device_get_unit(ctlp->dev);
842
843         kprintf("RocketPort%d (Version %s) %d ports.\n", unit,
844                 RocketPortVersion, num_ports);
845         rp_num_ports[unit] = num_ports;
846
847         ctlp->rp = rp = kmalloc(sizeof(struct rp_port) * num_ports, 
848                                 M_TTYS, M_WAITOK | M_ZERO);
849
850         count = unit * 32;      /* board times max ports per card SG */
851         for(i=count;i < (count + rp_num_ports[unit]);i++)
852                 minor_to_unit[i] = unit;
853
854         ctlp->tty = tty = kmalloc(sizeof(struct tty) * num_ports,
855                                     M_TTYS, M_WAITOK | M_ZERO);
856
857         crit_enter();
858         rp_addr(unit) = rp;
859         crit_exit();
860
861         for (i = 0 ; i < rp_num_ports[unit] ; i++) {
862                 make_dev(&rp_ops, ((unit + 1) << 16) | i,
863                           UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
864                           i <= 9 ? '0' + i : 'a' + i - 10);
865                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x20,
866                           UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
867                           i <= 9 ? '0' + i : 'a' + i - 10);
868                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x40,
869                           UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
870                           i <= 9 ? '0' + i : 'a' + i - 10);
871                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x80,
872                           UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
873                           i <= 9 ? '0' + i : 'a' + i - 10);
874                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xa0,
875                           UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
876                           i <= 9 ? '0' + i : 'a' + i - 10);
877                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xc0,
878                           UID_ROOT, GID_WHEEL, 0666, "cualR%c",
879                           i <= 9 ? '0' + i : 'a' + i - 10);
880         }
881
882         port = 0;
883         for(aiop=0; aiop < num_aiops; aiop++) {
884                 num_chan = sGetAiopNumChan(ctlp, aiop);
885                 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
886                         rp->rp_tty = tty;
887                         rp->rp_port = port;
888                         rp->rp_ctlp = ctlp;
889                         rp->rp_unit = unit;
890                         rp->rp_chan = chan;
891                         rp->rp_aiop = aiop;
892
893                         tty->t_line = 0;
894         /*              tty->t_termios = deftermios;
895         */
896                         rp->dtr_wait = 3 * hz;
897                         rp->it_in.c_iflag = 0;
898                         rp->it_in.c_oflag = 0;
899                         rp->it_in.c_cflag = TTYDEF_CFLAG;
900                         rp->it_in.c_lflag = 0;
901                         termioschars(&rp->it_in);
902         /*              termioschars(&tty->t_termios);
903         */
904                         rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
905                         rp->it_out = rp->it_in;
906
907                         rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
908                                 DELTA_CD | DELTA_CTS | DELTA_DSR;
909 #if 0 /* notdef */
910                         ChanStatus = sGetChanStatus(&rp->rp_channel);
911 #endif /* notdef */
912                         if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
913                                 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
914                                               unit, aiop, chan);
915                                 retval = ENXIO;
916                                 goto nogo;
917                         }
918                         ChanStatus = sGetChanStatus(&rp->rp_channel);
919                         rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
920                         line = (unit << 5) | (aiop << 3) | chan;
921                         rp_table(line) = rp;
922                 }
923         }
924
925         rp_ndevs++;
926         lwkt_reltoken(&tty_token);
927         return (0);
928
929 nogo:
930         rp_releaseresource(ctlp);
931         lwkt_reltoken(&tty_token);
932         return (retval);
933 }
934
935 void
936 rp_releaseresource(CONTROLLER_t *ctlp)
937 {
938         int i, unit;
939
940         lwkt_gettoken(&tty_token);
941         unit = device_get_unit(ctlp->dev);
942
943         if (ctlp->rp != NULL) {
944                 crit_enter();
945                 for (i = 0 ; i < NELEM(p_rp_addr) ; i++)
946                         if (p_rp_addr[i] == ctlp->rp)
947                                 p_rp_addr[i] = NULL;
948                 for (i = 0 ; i < NELEM(p_rp_table) ; i++)
949                         if (p_rp_table[i] == ctlp->rp)
950                                 p_rp_table[i] = NULL;
951                 crit_exit();
952                 kfree(ctlp->rp, M_DEVBUF);
953                 ctlp->rp = NULL;
954         }
955         if (ctlp->tty != NULL) {
956                 kfree(ctlp->tty, M_DEVBUF);
957                 ctlp->tty = NULL;
958         }
959         if (ctlp->dev != NULL)
960                 ctlp->dev = NULL;
961         dev_ops_remove_minor(&rp_ops, /*0xffff0000, */(unit + 1) << 16);
962         lwkt_reltoken(&tty_token);
963 }
964
965 int
966 rpopen(struct dev_open_args *ap)
967 {
968         cdev_t dev = ap->a_head.a_dev;
969         struct  rp_port *rp;
970         int     unit, port, mynor, umynor, flags;  /* SG */
971         struct  tty     *tp;
972         int     error;
973         unsigned int    IntMask, ChanStatus;
974
975         lwkt_gettoken(&tty_token);
976         if (!rp_initialized) {
977                 rp_initialized = 1;
978                 callout_init_mp(&rp_poll_ch);
979         }
980
981    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
982         port  = (minor(dev) & 0x1f);                /* SG */
983         mynor = (port + umynor);                    /* SG */
984         unit = minor_to_unit[mynor];
985         if (rp_addr(unit) == NULL) {
986                 lwkt_reltoken(&tty_token);
987                 return (ENXIO);
988         }
989         if(IS_CONTROL(dev)) {
990                 lwkt_reltoken(&tty_token);
991                 return(0);
992         }
993         rp = rp_addr(unit) + port;
994 /*      rp->rp_tty = &rp_tty[rp->rp_port];
995 */
996         callout_init_mp(&rp->wakeup_callout);
997         tp = rp->rp_tty;
998         dev->si_tty = tp;
999
1000         crit_enter();
1001
1002 open_top:
1003         while(rp->state & ~SET_DTR) {
1004                 error = tsleep(&rp->dtr_wait, PCATCH, "rpdtr", 0);
1005                 if(error != 0)
1006                         goto out;
1007         }
1008
1009         if(tp->t_state & TS_ISOPEN) {
1010                 if(IS_CALLOUT(dev)) {
1011                         if(!rp->active_out) {
1012                                 error = EBUSY;
1013                                 goto out;
1014                         }
1015                 } else {
1016                         if(rp->active_out) {
1017                                 if(ap->a_oflags & O_NONBLOCK) {
1018                                         error = EBUSY;
1019                                         goto out;
1020                                 }
1021                                 error = tsleep(&rp->active_out,
1022                                             PCATCH, "rpbi", 0);
1023                                 if(error != 0)
1024                                         goto out;
1025                                 goto open_top;
1026                         }
1027                 }
1028                 if(tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0) != 0) {
1029                         crit_exit();
1030                         error = EBUSY;
1031                         goto out2;
1032                 }
1033         }
1034         else {
1035                 tp->t_dev = dev;
1036                 tp->t_param = rpparam;
1037                 tp->t_oproc = rpstart;
1038                 tp->t_stop = rpstop;
1039                 tp->t_line = 0;
1040                 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1041                 tp->t_ififosize = 512;
1042                 tp->t_ispeedwat = (speed_t)-1;
1043                 tp->t_ospeedwat = (speed_t)-1;
1044                 flags = 0;
1045                 flags |= SET_RTS;
1046                 flags |= SET_DTR;
1047                 rp->rp_channel.TxControl[3] =
1048                         ((rp->rp_channel.TxControl[3]
1049                         & ~(SET_RTS | SET_DTR)) | flags);
1050                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1051                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1052                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1053                 sDisRxStatusMode(&rp->rp_channel);
1054                 sFlushRxFIFO(&rp->rp_channel);
1055                 sFlushTxFIFO(&rp->rp_channel);
1056
1057                 sEnInterrupts(&rp->rp_channel,
1058                         (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1059                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1060
1061                 sDisRxStatusMode(&rp->rp_channel);
1062                 sClrTxXOFF(&rp->rp_channel);
1063
1064 /*              sDisRTSFlowCtl(&rp->rp_channel);
1065                 sDisCTSFlowCtl(&rp->rp_channel);
1066 */
1067                 sDisTxSoftFlowCtl(&rp->rp_channel);
1068
1069                 sStartRxProcessor(&rp->rp_channel);
1070
1071                 sEnRxFIFO(&rp->rp_channel);
1072                 sEnTransmit(&rp->rp_channel);
1073
1074 /*              sSetDTR(&rp->rp_channel);
1075                 sSetRTS(&rp->rp_channel);
1076 */
1077
1078                 ++rp->wopeners;
1079                 error = rpparam(tp, &tp->t_termios);
1080                 --rp->wopeners;
1081                 if(error != 0) {
1082                         crit_exit();
1083                         lwkt_reltoken(&tty_token);
1084                         return(error);
1085                 }
1086
1087                 rp_num_ports_open++;
1088
1089                 IntMask = sGetChanIntID(&rp->rp_channel);
1090                 IntMask = IntMask & rp->rp_intmask;
1091                 ChanStatus = sGetChanStatus(&rp->rp_channel);
1092                 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1093                         if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1094                                         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1095                         }
1096                 }
1097
1098         if(rp_num_ports_open == 1)
1099                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1100
1101         }
1102
1103         if(!(ap->a_oflags&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1104                 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1105                 ++rp->wopeners;
1106                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "rpdcd", 0);
1107                 --rp->wopeners;
1108                 if(error != 0)
1109                         goto out;
1110                 goto open_top;
1111         }
1112         error = (*linesw[tp->t_line].l_open)(dev, tp);
1113
1114         rp_disc_optim(tp, &tp->t_termios);
1115         if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1116                 rp->active_out = TRUE;
1117
1118 /*      if(rp_num_ports_open == 1)
1119                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1120 */
1121 out:
1122         crit_exit();
1123         if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1124                 rphardclose(rp);
1125         }
1126 out2:
1127         if (error == 0)
1128                 device_busy(rp->rp_ctlp->dev);
1129         lwkt_reltoken(&tty_token);
1130         return(error);
1131 }
1132
1133 int
1134 rpclose(struct dev_close_args *ap)
1135 {
1136         cdev_t dev = ap->a_head.a_dev;
1137         int     unit, mynor, umynor, port; /* SG */
1138         struct  rp_port *rp;
1139         struct  tty     *tp;
1140         CHANNEL_t       *cp;
1141
1142         lwkt_gettoken(&tty_token);
1143    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1144         port  = (minor(dev) & 0x1f);                /* SG */
1145         mynor = (port + umynor);                    /* SG */
1146    unit = minor_to_unit[mynor];                /* SG */
1147
1148         if(IS_CONTROL(dev)) {
1149                 lwkt_reltoken(&tty_token);
1150                 return(0);
1151         }
1152         rp = rp_addr(unit) + port;
1153         cp = &rp->rp_channel;
1154         tp = rp->rp_tty;
1155
1156         crit_enter();
1157         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
1158         rp_disc_optim(tp, &tp->t_termios);
1159         rpstop(tp, FREAD | FWRITE);
1160         rphardclose(rp);
1161
1162         tp->t_state &= ~TS_BUSY;
1163         ttyclose(tp);
1164
1165         crit_exit();
1166
1167         device_unbusy(rp->rp_ctlp->dev);
1168
1169         lwkt_reltoken(&tty_token);
1170         return(0);
1171 }
1172
1173 /*
1174  * NOTE: Must be called with tty_token held
1175  */
1176 static void
1177 rphardclose(struct rp_port *rp)
1178 {
1179         int     mynor;
1180         struct  tty     *tp;
1181         CHANNEL_t       *cp;
1182
1183         ASSERT_LWKT_TOKEN_HELD(&tty_token);
1184         cp = &rp->rp_channel;
1185         tp = rp->rp_tty;
1186         mynor = MINOR_MAGIC(tp->t_dev);
1187
1188         sFlushRxFIFO(cp);
1189         sFlushTxFIFO(cp);
1190         sDisTransmit(cp);
1191         sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1192         sDisRTSFlowCtl(cp);
1193         sDisCTSFlowCtl(cp);
1194         sDisTxSoftFlowCtl(cp);
1195         sClrTxXOFF(cp);
1196
1197         if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1198                 sClrDTR(cp);
1199         }
1200         if(IS_CALLOUT(tp->t_dev)) {
1201                 sClrDTR(cp);
1202         }
1203         if(rp->dtr_wait != 0) {
1204                 callout_reset(&rp->wakeup_callout, rp->dtr_wait,
1205                               rpdtrwakeup, rp);
1206                 rp->state |= ~SET_DTR;
1207         }
1208
1209         rp->active_out = FALSE;
1210         wakeup(&rp->active_out);
1211         wakeup(TSA_CARR_ON(tp));
1212 }
1213
1214 static
1215 int
1216 rpwrite(struct dev_write_args *ap)
1217 {
1218         cdev_t dev = ap->a_head.a_dev;
1219         struct  rp_port *rp;
1220         struct  tty     *tp;
1221         int     unit, mynor, port, umynor, error = 0; /* SG */
1222
1223    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1224         port  = (minor(dev) & 0x1f);                /* SG */
1225         mynor = (port + umynor);                    /* SG */
1226    unit = minor_to_unit[mynor];                /* SG */
1227
1228         if(IS_CONTROL(dev))
1229                 return(ENODEV);
1230         lwkt_gettoken(&tty_token);
1231         rp = rp_addr(unit) + port;
1232         tp = rp->rp_tty;
1233         while(rp->rp_disable_writes) {
1234                 rp->rp_waiting = 1;
1235                 error = ttysleep(tp, (caddr_t)rp, PCATCH, "rp_write", 0);
1236                 if (error) {
1237                         lwkt_reltoken(&tty_token);
1238                         return(error);
1239                 }
1240         }
1241
1242         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1243         lwkt_reltoken(&tty_token);
1244         return error;
1245 }
1246
1247 static void
1248 rpdtrwakeup(void *chan)
1249 {
1250         struct  rp_port *rp;
1251
1252         lwkt_gettoken(&tty_token);
1253         rp = (struct rp_port *)chan;
1254         rp->state &= SET_DTR;
1255         wakeup(&rp->dtr_wait);
1256         lwkt_reltoken(&tty_token);
1257 }
1258
1259 int
1260 rpioctl(struct dev_ioctl_args *ap)
1261 {
1262         cdev_t dev = ap->a_head.a_dev;
1263         u_long cmd = ap->a_cmd;
1264         caddr_t data = ap->a_data;
1265         struct rp_port  *rp;
1266         CHANNEL_t       *cp;
1267         struct tty      *tp;
1268         int     unit, mynor, port, umynor;            /* SG */
1269         int     error = 0;
1270         int     arg, flags, result, ChanStatus;
1271         struct  termios *t;
1272
1273         lwkt_gettoken(&tty_token);
1274    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1275         port  = (minor(dev) & 0x1f);                /* SG */
1276         mynor = (port + umynor);                    /* SG */
1277         unit = minor_to_unit[mynor];
1278         rp = rp_addr(unit) + port;
1279
1280         if(IS_CONTROL(dev)) {
1281                 struct  termios *ct;
1282
1283                 switch (IS_CONTROL(dev)) {
1284                 case CONTROL_INIT_STATE:
1285                         ct =  IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1286                         break;
1287                 case CONTROL_LOCK_STATE:
1288                         ct =  IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1289                         break;
1290                 default:
1291                         lwkt_reltoken(&tty_token);
1292                         return(ENODEV);         /* /dev/nodev */
1293                 }
1294                 switch (cmd) {
1295                 case TIOCSETA:
1296                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1297                         if(error != 0) {
1298                                 lwkt_reltoken(&tty_token);
1299                                 return(error);
1300                         }
1301                         *ct = *(struct termios *)data;
1302                         lwkt_reltoken(&tty_token);
1303                         return(0);
1304                 case TIOCGETA:
1305                         *(struct termios *)data = *ct;
1306                         lwkt_reltoken(&tty_token);
1307                         return(0);
1308                 case TIOCGETD:
1309                         *(int *)data = TTYDISC;
1310                         lwkt_reltoken(&tty_token);
1311                         return(0);
1312                 case TIOCGWINSZ:
1313                         bzero(data, sizeof(struct winsize));
1314                         lwkt_reltoken(&tty_token);
1315                         return(0);
1316                 default:
1317                         lwkt_reltoken(&tty_token);
1318                         return(ENOTTY);
1319                 }
1320         }
1321
1322         tp = rp->rp_tty;
1323         cp = &rp->rp_channel;
1324
1325 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1326         term = tp->t_termios;
1327         oldcmd = cmd;
1328         error = ttsetcompat(tp, &cmd, data, &term);
1329         if(error != 0) {
1330                 lwkt_reltoken(&tty_token);
1331                 return(error);
1332         }
1333         if(cmd != oldcmd) {
1334                 data = (caddr_t)&term;
1335         }
1336 #endif
1337         if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1338                 int     cc;
1339                 struct  termios *dt = (struct termios *)data;
1340                 struct  termios *lt = IS_CALLOUT(dev)
1341                                         ? &rp->lt_out : &rp->lt_in;
1342
1343                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1344                                 | (dt->c_iflag & ~lt->c_iflag);
1345                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1346                                 | (dt->c_oflag & ~lt->c_oflag);
1347                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1348                                 | (dt->c_cflag & ~lt->c_cflag);
1349                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1350                                 | (dt->c_lflag & ~lt->c_lflag);
1351                 for(cc = 0; cc < NCCS; ++cc)
1352                         if(lt->c_cc[cc] != 0)
1353                                 dt->c_cc[cc] = tp->t_cc[cc];
1354                 if(lt->c_ispeed != 0)
1355                         dt->c_ispeed = tp->t_ispeed;
1356                 if(lt->c_ospeed != 0)
1357                         dt->c_ospeed = tp->t_ospeed;
1358         }
1359
1360         t = &tp->t_termios;
1361
1362         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data,
1363                                               ap->a_fflag, ap->a_cred);
1364         if(error != ENOIOCTL) {
1365                 lwkt_reltoken(&tty_token);
1366                 return(error);
1367         }
1368         crit_enter();
1369
1370         flags = rp->rp_channel.TxControl[3];
1371
1372         error = ttioctl(tp, cmd, data, ap->a_fflag);
1373         flags = rp->rp_channel.TxControl[3];
1374         rp_disc_optim(tp, &tp->t_termios);
1375         if(error != ENOIOCTL) {
1376                 crit_exit();
1377                 lwkt_reltoken(&tty_token);
1378                 return(error);
1379         }
1380         switch(cmd) {
1381         case TIOCSBRK:
1382                 sSendBreak(&rp->rp_channel);
1383                 break;
1384
1385         case TIOCCBRK:
1386                 sClrBreak(&rp->rp_channel);
1387                 break;
1388
1389         case TIOCSDTR:
1390                 sSetDTR(&rp->rp_channel);
1391                 sSetRTS(&rp->rp_channel);
1392                 break;
1393
1394         case TIOCCDTR:
1395                 sClrDTR(&rp->rp_channel);
1396                 break;
1397
1398         case TIOCMSET:
1399                 arg = *(int *) data;
1400                 flags = 0;
1401                 if(arg & TIOCM_RTS)
1402                         flags |= SET_RTS;
1403                 if(arg & TIOCM_DTR)
1404                         flags |= SET_DTR;
1405                 rp->rp_channel.TxControl[3] =
1406                         ((rp->rp_channel.TxControl[3]
1407                         & ~(SET_RTS | SET_DTR)) | flags);
1408                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1409                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1410                 break;
1411         case TIOCMBIS:
1412                 arg = *(int *) data;
1413                 flags = 0;
1414                 if(arg & TIOCM_RTS)
1415                         flags |= SET_RTS;
1416                 if(arg & TIOCM_DTR)
1417                         flags |= SET_DTR;
1418                         rp->rp_channel.TxControl[3] |= flags;
1419                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1420                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1421                 break;
1422         case TIOCMBIC:
1423                 arg = *(int *) data;
1424                 flags = 0;
1425                 if(arg & TIOCM_RTS)
1426                         flags |= SET_RTS;
1427                 if(arg & TIOCM_DTR)
1428                         flags |= SET_DTR;
1429                 rp->rp_channel.TxControl[3] &= ~flags;
1430                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1431                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1432                 break;
1433
1434
1435         case TIOCMGET:
1436                 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1437                 flags = rp->rp_channel.TxControl[3];
1438                 result = TIOCM_LE; /* always on while open for some reason */
1439                 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1440                         | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1441                         | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1442                         | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1443                         | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1444
1445                 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1446                 {
1447                         result |= TIOCM_RTS;
1448                 }
1449
1450                 *(int *)data = result;
1451                 break;
1452         case TIOCMSDTRWAIT:
1453                 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1454                 if(error != 0) {
1455                         crit_exit();
1456                         lwkt_reltoken(&tty_token);
1457                         return(error);
1458                 }
1459                 rp->dtr_wait = *(int *)data * hz/100;
1460                 break;
1461         case TIOCMGDTRWAIT:
1462                 *(int *)data = rp->dtr_wait * 100/hz;
1463                 break;
1464         default:
1465                 crit_exit();
1466                 lwkt_reltoken(&tty_token);
1467                 return ENOTTY;
1468         }
1469         crit_exit();
1470         lwkt_reltoken(&tty_token);
1471         return(0);
1472 }
1473
1474 static struct speedtab baud_table[] = {
1475         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
1476         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
1477         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
1478         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
1479         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
1480         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
1481                                 {B57600, BRD57600},     {B76800, BRD76800},
1482         {B115200, BRD115200},   {B230400, BRD230400},
1483         {-1,    -1}
1484 };
1485
1486 static int
1487 rpparam(struct tty *tp, struct termios *t)
1488 {
1489         struct rp_port  *rp;
1490         CHANNEL_t       *cp;
1491         int     unit, mynor, port, umynor;               /* SG */
1492         int     cflag, iflag, oflag, lflag;
1493         int     ospeed;
1494 #ifdef RPCLOCAL
1495         int     devshift;
1496 #endif
1497
1498         lwkt_gettoken(&tty_token);
1499    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1500         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1501         mynor = (port + umynor);                          /* SG */
1502
1503         unit = minor_to_unit[mynor];
1504         rp = rp_addr(unit) + port;
1505         cp = &rp->rp_channel;
1506         crit_enter();
1507
1508         cflag = t->c_cflag;
1509 #ifdef RPCLOCAL
1510         devshift = umynor / 32;
1511         devshift = 1 << devshift;
1512         if ( devshift & RPCLOCAL ) {
1513                 cflag |= CLOCAL;
1514         }
1515 #endif
1516         iflag = t->c_iflag;
1517         oflag = t->c_oflag;
1518         lflag = t->c_lflag;
1519
1520         ospeed = ttspeedtab(t->c_ispeed, baud_table);
1521         if(ospeed < 0 || t->c_ispeed != t->c_ospeed) {
1522                 crit_exit();
1523                 lwkt_reltoken(&tty_token);
1524                 return(EINVAL);
1525         }
1526
1527         tp->t_ispeed = t->c_ispeed;
1528         tp->t_ospeed = t->c_ospeed;
1529         tp->t_cflag = cflag;
1530         tp->t_iflag = iflag;
1531         tp->t_oflag = oflag;
1532         tp->t_lflag = lflag;
1533
1534         if(t->c_ospeed == 0) {
1535                 sClrDTR(cp);
1536                 crit_exit();
1537                 lwkt_reltoken(&tty_token);
1538                 return(0);
1539         }
1540         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1541
1542         /* Set baud rate ----- we only pay attention to ispeed */
1543         sSetDTR(cp);
1544         sSetRTS(cp);
1545         sSetBaud(cp, ospeed);
1546
1547         if(cflag & CSTOPB) {
1548                 sSetStop2(cp);
1549         } else {
1550                 sSetStop1(cp);
1551         }
1552
1553         if(cflag & PARENB) {
1554                 sEnParity(cp);
1555                 if(cflag & PARODD) {
1556                         sSetOddParity(cp);
1557                 } else {
1558                         sSetEvenParity(cp);
1559                 }
1560         }
1561         else {
1562                 sDisParity(cp);
1563         }
1564         if((cflag & CSIZE) == CS8) {
1565                 sSetData8(cp);
1566                 rp->rp_imask = 0xFF;
1567         } else {
1568                 sSetData7(cp);
1569                 rp->rp_imask = 0x7F;
1570         }
1571
1572         if(iflag & ISTRIP) {
1573                 rp->rp_imask &= 0x7F;
1574         }
1575
1576         if(cflag & CLOCAL) {
1577                 rp->rp_intmask &= ~DELTA_CD;
1578         } else {
1579                 rp->rp_intmask |= DELTA_CD;
1580         }
1581
1582         /* Put flow control stuff here */
1583
1584         if(cflag & CCTS_OFLOW) {
1585                 sEnCTSFlowCtl(cp);
1586         } else {
1587                 sDisCTSFlowCtl(cp);
1588         }
1589
1590         if(cflag & CRTS_IFLOW) {
1591                 rp->rp_rts_iflow = 1;
1592         } else {
1593                 rp->rp_rts_iflow = 0;
1594         }
1595
1596         if(cflag & CRTS_IFLOW) {
1597                 sEnRTSFlowCtl(cp);
1598         } else {
1599                 sDisRTSFlowCtl(cp);
1600         }
1601         rp_disc_optim(tp, t);
1602
1603         if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1604                 tp->t_state |= TS_CARR_ON;
1605                 wakeup(TSA_CARR_ON(tp));
1606         }
1607
1608 /*      tp->t_state |= TS_CAN_BYPASS_L_RINT;
1609         flags = rp->rp_channel.TxControl[3];
1610         if(flags & SET_DTR)
1611         else
1612         if(flags & SET_RTS)
1613         else
1614 */
1615         crit_exit();
1616
1617         lwkt_reltoken(&tty_token);
1618         return(0);
1619 }
1620
1621 static void
1622 rp_disc_optim(struct tty *tp, struct termios *t)
1623 {
1624         lwkt_gettoken(&tty_token);
1625         if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1626                 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1627                 &&(!(t->c_iflag & PARMRK)
1628                   ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1629                 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1630                 && linesw[tp->t_line].l_rint == ttyinput)
1631                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1632         else
1633                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1634         lwkt_reltoken(&tty_token);
1635 }
1636
1637 static void
1638 rpstart(struct tty *tp)
1639 {
1640         struct rp_port  *rp;
1641         CHANNEL_t       *cp;
1642         struct  clist   *qp;
1643         int     unit, mynor, port, umynor;               /* SG */
1644         char    flags;
1645         int     xmit_fifo_room;
1646         int     count, wcount;
1647
1648
1649         lwkt_gettoken(&tty_token);
1650    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1651         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1652         mynor = (port + umynor);                          /* SG */
1653         unit = minor_to_unit[mynor];
1654         rp = rp_addr(unit) + port;
1655         cp = &rp->rp_channel;
1656         flags = rp->rp_channel.TxControl[3];
1657         crit_enter();
1658
1659         if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1660                 ttwwakeup(tp);
1661                 crit_exit();
1662                 lwkt_reltoken(&tty_token);
1663                 return;
1664         }
1665         if(rp->rp_xmit_stopped) {
1666                 sEnTransmit(cp);
1667                 rp->rp_xmit_stopped = 0;
1668         }
1669         count = sGetTxCnt(cp);
1670
1671         if(tp->t_outq.c_cc == 0) {
1672                 if((tp->t_state & TS_BUSY) && (count == 0)) {
1673                         tp->t_state &= ~TS_BUSY;
1674                 }
1675                 ttwwakeup(tp);
1676                 crit_exit();
1677                 lwkt_reltoken(&tty_token);
1678                 return;
1679         }
1680         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1681         qp = &tp->t_outq;
1682         if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1683                 tp->t_state |= TS_BUSY;
1684                 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1685                 wcount = count >> 1;
1686                 if ( wcount ) {
1687                         rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1688                 }
1689                 if ( count & 1 ) {
1690                         rp_writech1(cp, sGetTxRxDataIO(cp),
1691                                     ((unsigned char *)(rp->TxBuf))[(count-1)]);
1692                 }
1693         }
1694         rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1695
1696         ttwwakeup(tp);
1697         crit_exit();
1698         lwkt_reltoken(&tty_token);
1699 }
1700
1701 static
1702 void
1703 rpstop(struct tty *tp, int flag)
1704 {
1705         struct rp_port  *rp;
1706         CHANNEL_t       *cp;
1707         int     unit, mynor, port, umynor;                  /* SG */
1708
1709         lwkt_gettoken(&tty_token);
1710    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1711         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1712         mynor = (port + umynor);                          /* SG */
1713         unit = minor_to_unit[mynor];
1714         rp = rp_addr(unit) + port;
1715         cp = &rp->rp_channel;
1716
1717         crit_enter();
1718
1719         if(tp->t_state & TS_BUSY) {
1720                 if((tp->t_state&TS_TTSTOP) == 0) {
1721                         sFlushTxFIFO(cp);
1722                 } else {
1723                         if(rp->rp_xmit_stopped == 0) {
1724                                 sDisTransmit(cp);
1725                                 rp->rp_xmit_stopped = 1;
1726                         }
1727                 }
1728         }
1729         crit_exit();
1730         rpstart(tp);
1731         lwkt_reltoken(&tty_token);
1732 }