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