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