Merge branch 'vendor/FILE' (early part)
[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 };
583
584 static int      rp_num_ports_open = 0;
585 static int      rp_ndevs = 0;
586 static int      minor_to_unit[128];
587 static int      rp_initialized;
588 static struct callout rp_poll_ch;
589
590 static int rp_num_ports[4];     /* Number of ports on each controller */
591
592 #define POLL_INTERVAL 1
593
594 #define CALLOUT_MASK            0x80
595 #define CONTROL_MASK            0x60
596 #define CONTROL_INIT_STATE      0x20
597 #define CONTROL_LOCK_STATE      0x40
598 #define DEV_UNIT(dev)   (MINOR_TO_UNIT(minor(dev))
599 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
600 #define MINOR_MAGIC(dev)        ((minor(dev)) & ~MINOR_MAGIC_MASK)
601 #define IS_CALLOUT(dev)         (minor(dev) & CALLOUT_MASK)
602 #define IS_CONTROL(dev)         (minor(dev) & CONTROL_MASK)
603
604 #define RP_ISMULTIPORT(dev)     ((dev)->id_flags & 0x1)
605 #define RP_MPMASTER(dev)        (((dev)->id_flags >> 8) & 0xff)
606 #define RP_NOTAST4(dev)         ((dev)->id_flags & 0x04)
607
608 static  struct  rp_port *p_rp_addr[4];
609 static  struct  rp_port *p_rp_table[MAX_RP_PORTS];
610 #define rp_addr(unit)   (p_rp_addr[unit])
611 #define rp_table(port)  (p_rp_table[port])
612
613 /*
614  * The top-level routines begin here
615  */
616
617 static  int     rpparam (struct tty *, struct termios *);
618 static  void    rpstart (struct tty *);
619 static  void    rpstop (struct tty *, int);
620 static  void    rphardclose     (struct rp_port *);
621 static  void    rp_disc_optim   (struct tty *tp, struct termios *t);
622
623 static void
624 rp_do_receive(struct rp_port *rp, struct tty *tp,
625                         CHANNEL_t *cp, unsigned int ChanStatus)
626 {
627         unsigned        int     CharNStat;
628         int     ToRecv, wRecv, ch, ttynocopy;
629
630         ToRecv = sGetRxCnt(cp);
631         if(ToRecv == 0)
632                 return;
633
634 /*      If status indicates there are errored characters in the
635         FIFO, then enter status mode (a word in FIFO holds
636         characters and status)
637 */
638
639         if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
640                 if(!(ChanStatus & STATMODE)) {
641                         ChanStatus |= STATMODE;
642                         sEnRxStatusMode(cp);
643                 }
644         }
645 /*
646         if we previously entered status mode then read down the
647         FIFO one word at a time, pulling apart the character and
648         the status. Update error counters depending on status.
649 */
650         if(ChanStatus & STATMODE) {
651                 while(ToRecv) {
652                         if(tp->t_state & TS_TBLOCK) {
653                                 break;
654                         }
655                         CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
656                         ch = CharNStat & 0xff;
657
658                         if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
659                                 ch |= TTY_FE;
660                         else if (CharNStat & STMPARITYH)
661                                 ch |= TTY_PE;
662                         else if (CharNStat & STMRCVROVRH)
663                                 rp->rp_overflows++;
664
665                         (*linesw[tp->t_line].l_rint)(ch, tp);
666                         ToRecv--;
667                 }
668 /*
669         After emtying FIFO in status mode, turn off status mode
670 */
671
672                 if(sGetRxCnt(cp) == 0) {
673                         sDisRxStatusMode(cp);
674                 }
675         } else {
676                 /*
677                  * Avoid the grotesquely inefficient lineswitch routine
678                  * (ttyinput) in "raw" mode.  It usually takes about 450
679                  * instructions (that's without canonical processing or echo!).
680                  * slinput is reasonably fast (usually 40 instructions plus
681                  * call overhead).
682                  */
683                 ToRecv = sGetRxCnt(cp);
684                 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
685                         if ( ToRecv > RXFIFO_SIZE ) {
686                                 ToRecv = RXFIFO_SIZE;
687                         }
688                         wRecv = ToRecv >> 1;
689                         if ( wRecv ) {
690                                 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
691                         }
692                         if ( ToRecv & 1 ) {
693                                 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
694                         }
695                         tk_nin += ToRecv;
696                         tk_rawcc += ToRecv;
697                         tp->t_rawcc += ToRecv;
698                         ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
699                         ttwakeup(tp);
700                 } else {
701                         while (ToRecv) {
702                                 if(tp->t_state & TS_TBLOCK) {
703                                         break;
704                                 }
705                                 ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
706                                 crit_enter();
707                                 (*linesw[tp->t_line].l_rint)(ch, tp);
708                                 crit_exit();
709                                 ToRecv--;
710                         }
711                 }
712         }
713 }
714
715 static void
716 rp_handle_port(struct rp_port *rp)
717 {
718         CHANNEL_t       *cp;
719         struct  tty     *tp;
720         unsigned        int     IntMask, ChanStatus;
721
722         if(!rp)
723                 return;
724
725         cp = &rp->rp_channel;
726         tp = rp->rp_tty;
727         IntMask = sGetChanIntID(cp);
728         IntMask = IntMask & rp->rp_intmask;
729         ChanStatus = sGetChanStatus(cp);
730         if(IntMask & RXF_TRIG)
731                 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
732                         rp_do_receive(rp, tp, cp, ChanStatus);
733                 }
734         if(IntMask & DELTA_CD) {
735                 if(ChanStatus & CD_ACT) {
736                         if(!(tp->t_state & TS_CARR_ON) ) {
737                                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
738                         }
739                 } else {
740                         if((tp->t_state & TS_CARR_ON)) {
741                                 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
742                                 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
743                                         rphardclose(rp);
744                                 }
745                         }
746                 }
747         }
748 /*      oldcts = rp->rp_cts;
749         rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
750         if(oldcts != rp->rp_cts) {
751                 kprintf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
752         }
753 */
754 }
755
756 static void rp_do_poll(void *not_used)
757 {
758         CONTROLLER_t    *ctl;
759         struct rp_port  *rp;
760         struct tty      *tp;
761         int     unit, aiop, ch, line, count;
762         unsigned char   CtlMask, AiopMask;
763
764         for(unit = 0; unit < rp_ndevs; unit++) {
765         rp = rp_addr(unit);
766         ctl = rp->rp_ctlp;
767         CtlMask = ctl->ctlmask(ctl);
768         for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
769                 if(CtlMask & 1) {
770                         AiopMask = sGetAiopIntStatus(ctl, aiop);
771                         for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
772                                 if(AiopMask & 1) {
773                                         line = (unit << 5) | (aiop << 3) | ch;
774                                         rp = rp_table(line);
775                                         rp_handle_port(rp);
776                                 }
777                         }
778                 }
779         }
780
781         for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
782                         line++, rp++) {
783                 tp = rp->rp_tty;
784                 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
785                         count = sGetTxCnt(&rp->rp_channel);
786                         if(count == 0)
787                                 tp->t_state &= ~(TS_BUSY);
788                         if(!(tp->t_state & TS_TTSTOP) &&
789                                 (count <= rp->rp_restart)) {
790                                 (*linesw[tp->t_line].l_start)(tp);
791                         }
792                 }
793         }
794         }
795         if(rp_num_ports_open)
796                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
797 }
798
799 int
800 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
801 {
802         int     unit;
803         int     num_chan;
804         int     aiop, chan, port;
805         int     ChanStatus, line, i, count;
806         int     retval;
807         struct  rp_port *rp;
808         struct  tty     *tty;
809
810         unit = device_get_unit(ctlp->dev);
811
812         kprintf("RocketPort%d (Version %s) %d ports.\n", unit,
813                 RocketPortVersion, num_ports);
814         rp_num_ports[unit] = num_ports;
815
816         ctlp->rp = rp = kmalloc(sizeof(struct rp_port) * num_ports, 
817                                 M_TTYS, M_WAITOK | M_ZERO);
818
819         count = unit * 32;      /* board times max ports per card SG */
820         for(i=count;i < (count + rp_num_ports[unit]);i++)
821                 minor_to_unit[i] = unit;
822
823         ctlp->tty = tty = kmalloc(sizeof(struct tty) * num_ports,
824                                     M_TTYS, M_WAITOK | M_ZERO);
825
826         crit_enter();
827         rp_addr(unit) = rp;
828         crit_exit();
829
830         dev_ops_add(&rp_ops, 0xffff0000, (unit + 1) << 16);
831         for (i = 0 ; i < rp_num_ports[unit] ; i++) {
832                 make_dev(&rp_ops, ((unit + 1) << 16) | i,
833                           UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
834                           i <= 9 ? '0' + i : 'a' + i - 10);
835                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x20,
836                           UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
837                           i <= 9 ? '0' + i : 'a' + i - 10);
838                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x40,
839                           UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
840                           i <= 9 ? '0' + i : 'a' + i - 10);
841                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x80,
842                           UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
843                           i <= 9 ? '0' + i : 'a' + i - 10);
844                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xa0,
845                           UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
846                           i <= 9 ? '0' + i : 'a' + i - 10);
847                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xc0,
848                           UID_ROOT, GID_WHEEL, 0666, "cualR%c",
849                           i <= 9 ? '0' + i : 'a' + i - 10);
850         }
851
852         port = 0;
853         for(aiop=0; aiop < num_aiops; aiop++) {
854                 num_chan = sGetAiopNumChan(ctlp, aiop);
855                 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
856                         rp->rp_tty = tty;
857                         rp->rp_port = port;
858                         rp->rp_ctlp = ctlp;
859                         rp->rp_unit = unit;
860                         rp->rp_chan = chan;
861                         rp->rp_aiop = aiop;
862
863                         tty->t_line = 0;
864         /*              tty->t_termios = deftermios;
865         */
866                         rp->dtr_wait = 3 * hz;
867                         rp->it_in.c_iflag = 0;
868                         rp->it_in.c_oflag = 0;
869                         rp->it_in.c_cflag = TTYDEF_CFLAG;
870                         rp->it_in.c_lflag = 0;
871                         termioschars(&rp->it_in);
872         /*              termioschars(&tty->t_termios);
873         */
874                         rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
875                         rp->it_out = rp->it_in;
876
877                         rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
878                                 DELTA_CD | DELTA_CTS | DELTA_DSR;
879 #if notdef
880                         ChanStatus = sGetChanStatus(&rp->rp_channel);
881 #endif /* notdef */
882                         if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
883                                 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
884                                               unit, aiop, chan);
885                                 retval = ENXIO;
886                                 goto nogo;
887                         }
888                         ChanStatus = sGetChanStatus(&rp->rp_channel);
889                         rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
890                         line = (unit << 5) | (aiop << 3) | chan;
891                         rp_table(line) = rp;
892                 }
893         }
894
895         rp_ndevs++;
896         return (0);
897
898 nogo:
899         rp_releaseresource(ctlp);
900
901         return (retval);
902 }
903
904 void
905 rp_releaseresource(CONTROLLER_t *ctlp)
906 {
907         int i, unit;
908
909         unit = device_get_unit(ctlp->dev);
910
911         if (ctlp->rp != NULL) {
912                 crit_enter();
913                 for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
914                         if (p_rp_addr[i] == ctlp->rp)
915                                 p_rp_addr[i] = NULL;
916                 for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
917                         if (p_rp_table[i] == ctlp->rp)
918                                 p_rp_table[i] = NULL;
919                 crit_exit();
920                 kfree(ctlp->rp, M_DEVBUF);
921                 ctlp->rp = NULL;
922         }
923         if (ctlp->tty != NULL) {
924                 kfree(ctlp->tty, M_DEVBUF);
925                 ctlp->tty = NULL;
926         }
927         if (ctlp->dev != NULL)
928                 ctlp->dev = NULL;
929         dev_ops_remove(&rp_ops, 0xffff0000, (unit + 1) << 16);
930 }
931
932 int
933 rpopen(struct dev_open_args *ap)
934 {
935         cdev_t dev = ap->a_head.a_dev;
936         struct  rp_port *rp;
937         int     unit, port, mynor, umynor, flags;  /* SG */
938         struct  tty     *tp;
939         int     error;
940         unsigned int    IntMask, ChanStatus;
941
942         if (!rp_initialized) {
943                 rp_initialized = 1;
944                 callout_init(&rp_poll_ch);
945         }
946
947    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
948         port  = (minor(dev) & 0x1f);                /* SG */
949         mynor = (port + umynor);                    /* SG */
950         unit = minor_to_unit[mynor];
951         if (rp_addr(unit) == NULL)
952                 return (ENXIO);
953         if(IS_CONTROL(dev))
954                 return(0);
955         rp = rp_addr(unit) + port;
956 /*      rp->rp_tty = &rp_tty[rp->rp_port];
957 */
958         callout_init(&rp->wakeup_callout);
959         tp = rp->rp_tty;
960         dev->si_tty = tp;
961
962         crit_enter();
963
964 open_top:
965         while(rp->state & ~SET_DTR) {
966                 error = tsleep(&rp->dtr_wait, PCATCH, "rpdtr", 0);
967                 if(error != 0)
968                         goto out;
969         }
970
971         if(tp->t_state & TS_ISOPEN) {
972                 if(IS_CALLOUT(dev)) {
973                         if(!rp->active_out) {
974                                 error = EBUSY;
975                                 goto out;
976                         }
977                 } else {
978                         if(rp->active_out) {
979                                 if(ap->a_oflags & O_NONBLOCK) {
980                                         error = EBUSY;
981                                         goto out;
982                                 }
983                                 error = tsleep(&rp->active_out,
984                                             PCATCH, "rpbi", 0);
985                                 if(error != 0)
986                                         goto out;
987                                 goto open_top;
988                         }
989                 }
990                 if(tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0) != 0) {
991                         crit_exit();
992                         error = EBUSY;
993                         goto out2;
994                 }
995         }
996         else {
997                 tp->t_dev = dev;
998                 tp->t_param = rpparam;
999                 tp->t_oproc = rpstart;
1000                 tp->t_stop = rpstop;
1001                 tp->t_line = 0;
1002                 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1003                 tp->t_ififosize = 512;
1004                 tp->t_ispeedwat = (speed_t)-1;
1005                 tp->t_ospeedwat = (speed_t)-1;
1006                 flags = 0;
1007                 flags |= SET_RTS;
1008                 flags |= SET_DTR;
1009                 rp->rp_channel.TxControl[3] =
1010                         ((rp->rp_channel.TxControl[3]
1011                         & ~(SET_RTS | SET_DTR)) | flags);
1012                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1013                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1014                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1015                 sDisRxStatusMode(&rp->rp_channel);
1016                 sFlushRxFIFO(&rp->rp_channel);
1017                 sFlushTxFIFO(&rp->rp_channel);
1018
1019                 sEnInterrupts(&rp->rp_channel,
1020                         (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1021                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1022
1023                 sDisRxStatusMode(&rp->rp_channel);
1024                 sClrTxXOFF(&rp->rp_channel);
1025
1026 /*              sDisRTSFlowCtl(&rp->rp_channel);
1027                 sDisCTSFlowCtl(&rp->rp_channel);
1028 */
1029                 sDisTxSoftFlowCtl(&rp->rp_channel);
1030
1031                 sStartRxProcessor(&rp->rp_channel);
1032
1033                 sEnRxFIFO(&rp->rp_channel);
1034                 sEnTransmit(&rp->rp_channel);
1035
1036 /*              sSetDTR(&rp->rp_channel);
1037                 sSetRTS(&rp->rp_channel);
1038 */
1039
1040                 ++rp->wopeners;
1041                 error = rpparam(tp, &tp->t_termios);
1042                 --rp->wopeners;
1043                 if(error != 0) {
1044                         crit_exit();
1045                         return(error);
1046                 }
1047
1048                 rp_num_ports_open++;
1049
1050                 IntMask = sGetChanIntID(&rp->rp_channel);
1051                 IntMask = IntMask & rp->rp_intmask;
1052                 ChanStatus = sGetChanStatus(&rp->rp_channel);
1053                 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1054                         if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1055                                         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1056                         }
1057                 }
1058
1059         if(rp_num_ports_open == 1)
1060                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1061
1062         }
1063
1064         if(!(ap->a_oflags&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1065                 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1066                 ++rp->wopeners;
1067                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "rpdcd", 0);
1068                 --rp->wopeners;
1069                 if(error != 0)
1070                         goto out;
1071                 goto open_top;
1072         }
1073         error = (*linesw[tp->t_line].l_open)(dev, tp);
1074
1075         rp_disc_optim(tp, &tp->t_termios);
1076         if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1077                 rp->active_out = TRUE;
1078
1079 /*      if(rp_num_ports_open == 1)
1080                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1081 */
1082 out:
1083         crit_exit();
1084         if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1085                 rphardclose(rp);
1086         }
1087 out2:
1088         if (error == 0)
1089                 device_busy(rp->rp_ctlp->dev);
1090         return(error);
1091 }
1092
1093 int
1094 rpclose(struct dev_close_args *ap)
1095 {
1096         cdev_t dev = ap->a_head.a_dev;
1097         int     unit, mynor, umynor, port; /* SG */
1098         struct  rp_port *rp;
1099         struct  tty     *tp;
1100         CHANNEL_t       *cp;
1101
1102    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1103         port  = (minor(dev) & 0x1f);                /* SG */
1104         mynor = (port + umynor);                    /* SG */
1105    unit = minor_to_unit[mynor];                /* SG */
1106
1107         if(IS_CONTROL(dev))
1108                 return(0);
1109         rp = rp_addr(unit) + port;
1110         cp = &rp->rp_channel;
1111         tp = rp->rp_tty;
1112
1113         crit_enter();
1114         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
1115         rp_disc_optim(tp, &tp->t_termios);
1116         rpstop(tp, FREAD | FWRITE);
1117         rphardclose(rp);
1118
1119         tp->t_state &= ~TS_BUSY;
1120         ttyclose(tp);
1121
1122         crit_exit();
1123
1124         device_unbusy(rp->rp_ctlp->dev);
1125
1126         return(0);
1127 }
1128
1129 static void
1130 rphardclose(struct rp_port *rp)
1131 {
1132         int     mynor;
1133         struct  tty     *tp;
1134         CHANNEL_t       *cp;
1135
1136         cp = &rp->rp_channel;
1137         tp = rp->rp_tty;
1138         mynor = MINOR_MAGIC(tp->t_dev);
1139
1140         sFlushRxFIFO(cp);
1141         sFlushTxFIFO(cp);
1142         sDisTransmit(cp);
1143         sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1144         sDisRTSFlowCtl(cp);
1145         sDisCTSFlowCtl(cp);
1146         sDisTxSoftFlowCtl(cp);
1147         sClrTxXOFF(cp);
1148
1149         if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1150                 sClrDTR(cp);
1151         }
1152         if(IS_CALLOUT(tp->t_dev)) {
1153                 sClrDTR(cp);
1154         }
1155         if(rp->dtr_wait != 0) {
1156                 callout_reset(&rp->wakeup_callout, rp->dtr_wait,
1157                               rpdtrwakeup, rp);
1158                 rp->state |= ~SET_DTR;
1159         }
1160
1161         rp->active_out = FALSE;
1162         wakeup(&rp->active_out);
1163         wakeup(TSA_CARR_ON(tp));
1164 }
1165
1166 static
1167 int
1168 rpwrite(struct dev_write_args *ap)
1169 {
1170         cdev_t dev = ap->a_head.a_dev;
1171         struct  rp_port *rp;
1172         struct  tty     *tp;
1173         int     unit, mynor, port, umynor, error = 0; /* SG */
1174
1175    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1176         port  = (minor(dev) & 0x1f);                /* SG */
1177         mynor = (port + umynor);                    /* SG */
1178    unit = minor_to_unit[mynor];                /* SG */
1179
1180         if(IS_CONTROL(dev))
1181                 return(ENODEV);
1182         rp = rp_addr(unit) + port;
1183         tp = rp->rp_tty;
1184         while(rp->rp_disable_writes) {
1185                 rp->rp_waiting = 1;
1186                 error = ttysleep(tp, (caddr_t)rp, PCATCH, "rp_write", 0);
1187                 if (error)
1188                         return(error);
1189         }
1190
1191         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1192         return error;
1193 }
1194
1195 static void
1196 rpdtrwakeup(void *chan)
1197 {
1198         struct  rp_port *rp;
1199
1200         rp = (struct rp_port *)chan;
1201         rp->state &= SET_DTR;
1202         wakeup(&rp->dtr_wait);
1203 }
1204
1205 int
1206 rpioctl(struct dev_ioctl_args *ap)
1207 {
1208         cdev_t dev = ap->a_head.a_dev;
1209         u_long cmd = ap->a_cmd;
1210         caddr_t data = ap->a_data;
1211         struct rp_port  *rp;
1212         CHANNEL_t       *cp;
1213         struct tty      *tp;
1214         int     unit, mynor, port, umynor;            /* SG */
1215         int     error = 0;
1216         int     arg, flags, result, ChanStatus;
1217         struct  termios *t;
1218
1219    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1220         port  = (minor(dev) & 0x1f);                /* SG */
1221         mynor = (port + umynor);                    /* SG */
1222         unit = minor_to_unit[mynor];
1223         rp = rp_addr(unit) + port;
1224
1225         if(IS_CONTROL(dev)) {
1226                 struct  termios *ct;
1227
1228                 switch (IS_CONTROL(dev)) {
1229                 case CONTROL_INIT_STATE:
1230                         ct =  IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1231                         break;
1232                 case CONTROL_LOCK_STATE:
1233                         ct =  IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1234                         break;
1235                 default:
1236                         return(ENODEV);         /* /dev/nodev */
1237                 }
1238                 switch (cmd) {
1239                 case TIOCSETA:
1240                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1241                         if(error != 0)
1242                                 return(error);
1243                         *ct = *(struct termios *)data;
1244                         return(0);
1245                 case TIOCGETA:
1246                         *(struct termios *)data = *ct;
1247                         return(0);
1248                 case TIOCGETD:
1249                         *(int *)data = TTYDISC;
1250                         return(0);
1251                 case TIOCGWINSZ:
1252                         bzero(data, sizeof(struct winsize));
1253                         return(0);
1254                 default:
1255                         return(ENOTTY);
1256                 }
1257         }
1258
1259         tp = rp->rp_tty;
1260         cp = &rp->rp_channel;
1261
1262 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1263         term = tp->t_termios;
1264         oldcmd = cmd;
1265         error = ttsetcompat(tp, &cmd, data, &term);
1266         if(error != 0)
1267                 return(error);
1268         if(cmd != oldcmd) {
1269                 data = (caddr_t)&term;
1270         }
1271 #endif
1272         if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1273                 int     cc;
1274                 struct  termios *dt = (struct termios *)data;
1275                 struct  termios *lt = IS_CALLOUT(dev)
1276                                         ? &rp->lt_out : &rp->lt_in;
1277
1278                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1279                                 | (dt->c_iflag & ~lt->c_iflag);
1280                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1281                                 | (dt->c_oflag & ~lt->c_oflag);
1282                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1283                                 | (dt->c_cflag & ~lt->c_cflag);
1284                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1285                                 | (dt->c_lflag & ~lt->c_lflag);
1286                 for(cc = 0; cc < NCCS; ++cc)
1287                         if(lt->c_cc[cc] != 0)
1288                                 dt->c_cc[cc] = tp->t_cc[cc];
1289                 if(lt->c_ispeed != 0)
1290                         dt->c_ispeed = tp->t_ispeed;
1291                 if(lt->c_ospeed != 0)
1292                         dt->c_ospeed = tp->t_ospeed;
1293         }
1294
1295         t = &tp->t_termios;
1296
1297         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data,
1298                                               ap->a_fflag, ap->a_cred);
1299         if(error != ENOIOCTL) {
1300                 return(error);
1301         }
1302         crit_enter();
1303
1304         flags = rp->rp_channel.TxControl[3];
1305
1306         error = ttioctl(tp, cmd, data, ap->a_fflag);
1307         flags = rp->rp_channel.TxControl[3];
1308         rp_disc_optim(tp, &tp->t_termios);
1309         if(error != ENOIOCTL) {
1310                 crit_exit();
1311                 return(error);
1312         }
1313         switch(cmd) {
1314         case TIOCSBRK:
1315                 sSendBreak(&rp->rp_channel);
1316                 break;
1317
1318         case TIOCCBRK:
1319                 sClrBreak(&rp->rp_channel);
1320                 break;
1321
1322         case TIOCSDTR:
1323                 sSetDTR(&rp->rp_channel);
1324                 sSetRTS(&rp->rp_channel);
1325                 break;
1326
1327         case TIOCCDTR:
1328                 sClrDTR(&rp->rp_channel);
1329                 break;
1330
1331         case TIOCMSET:
1332                 arg = *(int *) data;
1333                 flags = 0;
1334                 if(arg & TIOCM_RTS)
1335                         flags |= SET_RTS;
1336                 if(arg & TIOCM_DTR)
1337                         flags |= SET_DTR;
1338                 rp->rp_channel.TxControl[3] =
1339                         ((rp->rp_channel.TxControl[3]
1340                         & ~(SET_RTS | SET_DTR)) | flags);
1341                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1342                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1343                 break;
1344         case TIOCMBIS:
1345                 arg = *(int *) data;
1346                 flags = 0;
1347                 if(arg & TIOCM_RTS)
1348                         flags |= SET_RTS;
1349                 if(arg & TIOCM_DTR)
1350                         flags |= SET_DTR;
1351                         rp->rp_channel.TxControl[3] |= flags;
1352                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1353                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1354                 break;
1355         case TIOCMBIC:
1356                 arg = *(int *) data;
1357                 flags = 0;
1358                 if(arg & TIOCM_RTS)
1359                         flags |= SET_RTS;
1360                 if(arg & TIOCM_DTR)
1361                         flags |= SET_DTR;
1362                 rp->rp_channel.TxControl[3] &= ~flags;
1363                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1364                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1365                 break;
1366
1367
1368         case TIOCMGET:
1369                 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1370                 flags = rp->rp_channel.TxControl[3];
1371                 result = TIOCM_LE; /* always on while open for some reason */
1372                 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1373                         | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1374                         | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1375                         | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1376                         | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1377
1378                 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1379                 {
1380                         result |= TIOCM_RTS;
1381                 }
1382
1383                 *(int *)data = result;
1384                 break;
1385         case TIOCMSDTRWAIT:
1386                 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1387                 if(error != 0) {
1388                         crit_exit();
1389                         return(error);
1390                 }
1391                 rp->dtr_wait = *(int *)data * hz/100;
1392                 break;
1393         case TIOCMGDTRWAIT:
1394                 *(int *)data = rp->dtr_wait * 100/hz;
1395                 break;
1396         default:
1397                 crit_exit();
1398                 return ENOTTY;
1399         }
1400         crit_exit();
1401         return(0);
1402 }
1403
1404 static struct speedtab baud_table[] = {
1405         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
1406         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
1407         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
1408         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
1409         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
1410         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
1411                                 {B57600, BRD57600},     {B76800, BRD76800},
1412         {B115200, BRD115200},   {B230400, BRD230400},
1413         {-1,    -1}
1414 };
1415
1416 static int
1417 rpparam(struct tty *tp, struct termios *t)
1418 {
1419         struct rp_port  *rp;
1420         CHANNEL_t       *cp;
1421         int     unit, mynor, port, umynor;               /* SG */
1422         int     cflag, iflag, oflag, lflag;
1423         int     ospeed;
1424 #ifdef RPCLOCAL
1425         int     devshift;
1426 #endif
1427
1428
1429    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1430         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1431         mynor = (port + umynor);                          /* SG */
1432
1433         unit = minor_to_unit[mynor];
1434         rp = rp_addr(unit) + port;
1435         cp = &rp->rp_channel;
1436         crit_enter();
1437
1438         cflag = t->c_cflag;
1439 #ifdef RPCLOCAL
1440         devshift = umynor / 32;
1441         devshift = 1 << devshift;
1442         if ( devshift & RPCLOCAL ) {
1443                 cflag |= CLOCAL;
1444         }
1445 #endif
1446         iflag = t->c_iflag;
1447         oflag = t->c_oflag;
1448         lflag = t->c_lflag;
1449
1450         ospeed = ttspeedtab(t->c_ispeed, baud_table);
1451         if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1452                 return(EINVAL);
1453
1454         tp->t_ispeed = t->c_ispeed;
1455         tp->t_ospeed = t->c_ospeed;
1456         tp->t_cflag = cflag;
1457         tp->t_iflag = iflag;
1458         tp->t_oflag = oflag;
1459         tp->t_lflag = lflag;
1460
1461         if(t->c_ospeed == 0) {
1462                 sClrDTR(cp);
1463                 return(0);
1464         }
1465         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1466
1467         /* Set baud rate ----- we only pay attention to ispeed */
1468         sSetDTR(cp);
1469         sSetRTS(cp);
1470         sSetBaud(cp, ospeed);
1471
1472         if(cflag & CSTOPB) {
1473                 sSetStop2(cp);
1474         } else {
1475                 sSetStop1(cp);
1476         }
1477
1478         if(cflag & PARENB) {
1479                 sEnParity(cp);
1480                 if(cflag & PARODD) {
1481                         sSetOddParity(cp);
1482                 } else {
1483                         sSetEvenParity(cp);
1484                 }
1485         }
1486         else {
1487                 sDisParity(cp);
1488         }
1489         if((cflag & CSIZE) == CS8) {
1490                 sSetData8(cp);
1491                 rp->rp_imask = 0xFF;
1492         } else {
1493                 sSetData7(cp);
1494                 rp->rp_imask = 0x7F;
1495         }
1496
1497         if(iflag & ISTRIP) {
1498                 rp->rp_imask &= 0x7F;
1499         }
1500
1501         if(cflag & CLOCAL) {
1502                 rp->rp_intmask &= ~DELTA_CD;
1503         } else {
1504                 rp->rp_intmask |= DELTA_CD;
1505         }
1506
1507         /* Put flow control stuff here */
1508
1509         if(cflag & CCTS_OFLOW) {
1510                 sEnCTSFlowCtl(cp);
1511         } else {
1512                 sDisCTSFlowCtl(cp);
1513         }
1514
1515         if(cflag & CRTS_IFLOW) {
1516                 rp->rp_rts_iflow = 1;
1517         } else {
1518                 rp->rp_rts_iflow = 0;
1519         }
1520
1521         if(cflag & CRTS_IFLOW) {
1522                 sEnRTSFlowCtl(cp);
1523         } else {
1524                 sDisRTSFlowCtl(cp);
1525         }
1526         rp_disc_optim(tp, t);
1527
1528         if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1529                 tp->t_state |= TS_CARR_ON;
1530                 wakeup(TSA_CARR_ON(tp));
1531         }
1532
1533 /*      tp->t_state |= TS_CAN_BYPASS_L_RINT;
1534         flags = rp->rp_channel.TxControl[3];
1535         if(flags & SET_DTR)
1536         else
1537         if(flags & SET_RTS)
1538         else
1539 */
1540         crit_exit();
1541
1542         return(0);
1543 }
1544
1545 static void
1546 rp_disc_optim(struct tty *tp, struct termios *t)
1547 {
1548         if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1549                 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1550                 &&(!(t->c_iflag & PARMRK)
1551                   ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1552                 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1553                 && linesw[tp->t_line].l_rint == ttyinput)
1554                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1555         else
1556                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1557 }
1558
1559 static void
1560 rpstart(struct tty *tp)
1561 {
1562         struct rp_port  *rp;
1563         CHANNEL_t       *cp;
1564         struct  clist   *qp;
1565         int     unit, mynor, port, umynor;               /* SG */
1566         char    flags;
1567         int     xmit_fifo_room;
1568         int     count, wcount;
1569
1570
1571    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1572         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1573         mynor = (port + umynor);                          /* SG */
1574         unit = minor_to_unit[mynor];
1575         rp = rp_addr(unit) + port;
1576         cp = &rp->rp_channel;
1577         flags = rp->rp_channel.TxControl[3];
1578         crit_enter();
1579
1580         if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1581                 ttwwakeup(tp);
1582                 crit_exit();
1583                 return;
1584         }
1585         if(rp->rp_xmit_stopped) {
1586                 sEnTransmit(cp);
1587                 rp->rp_xmit_stopped = 0;
1588         }
1589         count = sGetTxCnt(cp);
1590
1591         if(tp->t_outq.c_cc == 0) {
1592                 if((tp->t_state & TS_BUSY) && (count == 0)) {
1593                         tp->t_state &= ~TS_BUSY;
1594                 }
1595                 ttwwakeup(tp);
1596                 crit_exit();
1597                 return;
1598         }
1599         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1600         qp = &tp->t_outq;
1601         if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1602                 tp->t_state |= TS_BUSY;
1603                 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1604                 wcount = count >> 1;
1605                 if ( wcount ) {
1606                         rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1607                 }
1608                 if ( count & 1 ) {
1609                         rp_writech1(cp, sGetTxRxDataIO(cp),
1610                                     ((unsigned char *)(rp->TxBuf))[(count-1)]);
1611                 }
1612         }
1613         rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1614
1615         ttwwakeup(tp);
1616         crit_exit();
1617 }
1618
1619 static
1620 void
1621 rpstop(struct tty *tp, int flag)
1622 {
1623         struct rp_port  *rp;
1624         CHANNEL_t       *cp;
1625         int     unit, mynor, port, umynor;                  /* SG */
1626
1627    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1628         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1629         mynor = (port + umynor);                          /* SG */
1630         unit = minor_to_unit[mynor];
1631         rp = rp_addr(unit) + port;
1632         cp = &rp->rp_channel;
1633
1634         crit_enter();
1635
1636         if(tp->t_state & TS_BUSY) {
1637                 if((tp->t_state&TS_TTSTOP) == 0) {
1638                         sFlushTxFIFO(cp);
1639                 } else {
1640                         if(rp->rp_xmit_stopped == 0) {
1641                                 sDisTransmit(cp);
1642                                 rp->rp_xmit_stopped = 1;
1643                         }
1644                 }
1645         }
1646         crit_exit();
1647         rpstart(tp);
1648 }