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