- Rewrite Buffer object to maintain only write pointer. There is no
[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.13 2004/12/03 17:59:20 joerg 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
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 cdevsw rp_cdevsw = {
575         /* name */      "rp",
576         /* maj */       CDEV_MAJOR,
577         /* flags */     D_TTY,
578         /* port */      NULL,
579         /* clone */     NULL,
580
581         /* open */      rpopen,
582         /* close */     rpclose,
583         /* read */      ttyread,
584         /* write */     rpwrite,
585         /* ioctl */     rpioctl,
586         /* poll */      ttypoll,
587         /* mmap */      nommap,
588         /* strategy */  nostrategy,
589         /* dump */      nodump,
590         /* psize */     nopsize
591 };
592
593 static int      rp_num_ports_open = 0;
594 static int      rp_ndevs = 0;
595 static int      minor_to_unit[128];
596 static int      rp_initialized;
597 static struct callout rp_poll_ch;
598
599 static int rp_num_ports[4];     /* Number of ports on each controller */
600
601 #define POLL_INTERVAL 1
602
603 #define CALLOUT_MASK            0x80
604 #define CONTROL_MASK            0x60
605 #define CONTROL_INIT_STATE      0x20
606 #define CONTROL_LOCK_STATE      0x40
607 #define DEV_UNIT(dev)   (MINOR_TO_UNIT(minor(dev))
608 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
609 #define MINOR_MAGIC(dev)        ((minor(dev)) & ~MINOR_MAGIC_MASK)
610 #define IS_CALLOUT(dev)         (minor(dev) & CALLOUT_MASK)
611 #define IS_CONTROL(dev)         (minor(dev) & CONTROL_MASK)
612
613 #define RP_ISMULTIPORT(dev)     ((dev)->id_flags & 0x1)
614 #define RP_MPMASTER(dev)        (((dev)->id_flags >> 8) & 0xff)
615 #define RP_NOTAST4(dev)         ((dev)->id_flags & 0x04)
616
617 static  struct  rp_port *p_rp_addr[4];
618 static  struct  rp_port *p_rp_table[MAX_RP_PORTS];
619 #define rp_addr(unit)   (p_rp_addr[unit])
620 #define rp_table(port)  (p_rp_table[port])
621
622 /*
623  * The top-level routines begin here
624  */
625
626 static  int     rpparam (struct tty *, struct termios *);
627 static  void    rpstart (struct tty *);
628 static  void    rpstop (struct tty *, int);
629 static  void    rphardclose     (struct rp_port *);
630 static  void    rp_disc_optim   (struct tty *tp, struct termios *t);
631
632 static void
633 rp_do_receive(struct rp_port *rp, struct tty *tp,
634                         CHANNEL_t *cp, unsigned int ChanStatus)
635 {
636         int     spl;
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                                 spl = spltty();
717                                 (*linesw[tp->t_line].l_rint)(ch, tp);
718                                 splx(spl);
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     oldspl, 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         oldspl = spltty();
837         rp_addr(unit) = rp;
838         splx(oldspl);
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, s, unit;
918
919         unit = device_get_unit(ctlp->dev);
920
921         if (ctlp->rp != NULL) {
922                 s = spltty();
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                 splx(s);
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     oldspl, 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         oldspl = spltty();
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                         splx(oldspl);
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                         splx(oldspl);
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         splx(oldspl);
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     oldspl, 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         oldspl = spltty();
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         splx(oldspl);
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     oldspl;
1223         int     error = 0;
1224         int     arg, flags, result, ChanStatus;
1225         struct  termios *t;
1226
1227    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1228         port  = (minor(dev) & 0x1f);                /* SG */
1229         mynor = (port + umynor);                    /* SG */
1230         unit = minor_to_unit[mynor];
1231         rp = rp_addr(unit) + port;
1232
1233         if(IS_CONTROL(dev)) {
1234                 struct  termios *ct;
1235
1236                 switch (IS_CONTROL(dev)) {
1237                 case CONTROL_INIT_STATE:
1238                         ct =  IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1239                         break;
1240                 case CONTROL_LOCK_STATE:
1241                         ct =  IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1242                         break;
1243                 default:
1244                         return(ENODEV);         /* /dev/nodev */
1245                 }
1246                 switch (cmd) {
1247                 case TIOCSETA:
1248                         error = suser(td);
1249                         if(error != 0)
1250                                 return(error);
1251                         *ct = *(struct termios *)data;
1252                         return(0);
1253                 case TIOCGETA:
1254                         *(struct termios *)data = *ct;
1255                         return(0);
1256                 case TIOCGETD:
1257                         *(int *)data = TTYDISC;
1258                         return(0);
1259                 case TIOCGWINSZ:
1260                         bzero(data, sizeof(struct winsize));
1261                         return(0);
1262                 default:
1263                         return(ENOTTY);
1264                 }
1265         }
1266
1267         tp = rp->rp_tty;
1268         cp = &rp->rp_channel;
1269
1270 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1271         term = tp->t_termios;
1272         oldcmd = cmd;
1273         error = ttsetcompat(tp, &cmd, data, &term);
1274         if(error != 0)
1275                 return(error);
1276         if(cmd != oldcmd) {
1277                 data = (caddr_t)&term;
1278         }
1279 #endif
1280         if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1281                 int     cc;
1282                 struct  termios *dt = (struct termios *)data;
1283                 struct  termios *lt = IS_CALLOUT(dev)
1284                                         ? &rp->lt_out : &rp->lt_in;
1285
1286                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1287                                 | (dt->c_iflag & ~lt->c_iflag);
1288                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1289                                 | (dt->c_oflag & ~lt->c_oflag);
1290                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1291                                 | (dt->c_cflag & ~lt->c_cflag);
1292                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1293                                 | (dt->c_lflag & ~lt->c_lflag);
1294                 for(cc = 0; cc < NCCS; ++cc)
1295                         if(lt->c_cc[cc] != 0)
1296                                 dt->c_cc[cc] = tp->t_cc[cc];
1297                 if(lt->c_ispeed != 0)
1298                         dt->c_ispeed = tp->t_ispeed;
1299                 if(lt->c_ospeed != 0)
1300                         dt->c_ospeed = tp->t_ospeed;
1301         }
1302
1303         t = &tp->t_termios;
1304
1305         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
1306         if(error != ENOIOCTL) {
1307                 return(error);
1308         }
1309         oldspl = spltty();
1310
1311         flags = rp->rp_channel.TxControl[3];
1312
1313         error = ttioctl(tp, cmd, data, flag);
1314         flags = rp->rp_channel.TxControl[3];
1315         rp_disc_optim(tp, &tp->t_termios);
1316         if(error != ENOIOCTL) {
1317                 splx(oldspl);
1318                 return(error);
1319         }
1320         switch(cmd) {
1321         case TIOCSBRK:
1322                 sSendBreak(&rp->rp_channel);
1323                 break;
1324
1325         case TIOCCBRK:
1326                 sClrBreak(&rp->rp_channel);
1327                 break;
1328
1329         case TIOCSDTR:
1330                 sSetDTR(&rp->rp_channel);
1331                 sSetRTS(&rp->rp_channel);
1332                 break;
1333
1334         case TIOCCDTR:
1335                 sClrDTR(&rp->rp_channel);
1336                 break;
1337
1338         case TIOCMSET:
1339                 arg = *(int *) data;
1340                 flags = 0;
1341                 if(arg & TIOCM_RTS)
1342                         flags |= SET_RTS;
1343                 if(arg & TIOCM_DTR)
1344                         flags |= SET_DTR;
1345                 rp->rp_channel.TxControl[3] =
1346                         ((rp->rp_channel.TxControl[3]
1347                         & ~(SET_RTS | SET_DTR)) | flags);
1348                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1349                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1350                 break;
1351         case TIOCMBIS:
1352                 arg = *(int *) data;
1353                 flags = 0;
1354                 if(arg & TIOCM_RTS)
1355                         flags |= SET_RTS;
1356                 if(arg & TIOCM_DTR)
1357                         flags |= SET_DTR;
1358                         rp->rp_channel.TxControl[3] |= flags;
1359                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1360                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1361                 break;
1362         case TIOCMBIC:
1363                 arg = *(int *) data;
1364                 flags = 0;
1365                 if(arg & TIOCM_RTS)
1366                         flags |= SET_RTS;
1367                 if(arg & TIOCM_DTR)
1368                         flags |= SET_DTR;
1369                 rp->rp_channel.TxControl[3] &= ~flags;
1370                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1371                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1372                 break;
1373
1374
1375         case TIOCMGET:
1376                 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1377                 flags = rp->rp_channel.TxControl[3];
1378                 result = TIOCM_LE; /* always on while open for some reason */
1379                 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1380                         | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1381                         | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1382                         | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1383                         | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1384
1385                 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1386                 {
1387                         result |= TIOCM_RTS;
1388                 }
1389
1390                 *(int *)data = result;
1391                 break;
1392         case TIOCMSDTRWAIT:
1393                 error = suser(td);
1394                 if(error != 0) {
1395                         splx(oldspl);
1396                         return(error);
1397                 }
1398                 rp->dtr_wait = *(int *)data * hz/100;
1399                 break;
1400         case TIOCMGDTRWAIT:
1401                 *(int *)data = rp->dtr_wait * 100/hz;
1402                 break;
1403         default:
1404                 splx(oldspl);
1405                 return ENOTTY;
1406         }
1407         splx(oldspl);
1408         return(0);
1409 }
1410
1411 static struct speedtab baud_table[] = {
1412         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
1413         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
1414         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
1415         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
1416         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
1417         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
1418                                 {B57600, BRD57600},     {B76800, BRD76800},
1419         {B115200, BRD115200},   {B230400, BRD230400},
1420         {-1,    -1}
1421 };
1422
1423 static int
1424 rpparam(tp, t)
1425         struct tty *tp;
1426         struct termios *t;
1427 {
1428         struct rp_port  *rp;
1429         CHANNEL_t       *cp;
1430         int     unit, mynor, port, umynor;               /* SG */
1431         int     oldspl, cflag, iflag, oflag, lflag;
1432         int     ospeed;
1433 #ifdef RPCLOCAL
1434         int     devshift;
1435 #endif
1436
1437
1438    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1439         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1440         mynor = (port + umynor);                          /* SG */
1441
1442         unit = minor_to_unit[mynor];
1443         rp = rp_addr(unit) + port;
1444         cp = &rp->rp_channel;
1445         oldspl = spltty();
1446
1447         cflag = t->c_cflag;
1448 #ifdef RPCLOCAL
1449         devshift = umynor / 32;
1450         devshift = 1 << devshift;
1451         if ( devshift & RPCLOCAL ) {
1452                 cflag |= CLOCAL;
1453         }
1454 #endif
1455         iflag = t->c_iflag;
1456         oflag = t->c_oflag;
1457         lflag = t->c_lflag;
1458
1459         ospeed = ttspeedtab(t->c_ispeed, baud_table);
1460         if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1461                 return(EINVAL);
1462
1463         tp->t_ispeed = t->c_ispeed;
1464         tp->t_ospeed = t->c_ospeed;
1465         tp->t_cflag = cflag;
1466         tp->t_iflag = iflag;
1467         tp->t_oflag = oflag;
1468         tp->t_lflag = lflag;
1469
1470         if(t->c_ospeed == 0) {
1471                 sClrDTR(cp);
1472                 return(0);
1473         }
1474         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1475
1476         /* Set baud rate ----- we only pay attention to ispeed */
1477         sSetDTR(cp);
1478         sSetRTS(cp);
1479         sSetBaud(cp, ospeed);
1480
1481         if(cflag & CSTOPB) {
1482                 sSetStop2(cp);
1483         } else {
1484                 sSetStop1(cp);
1485         }
1486
1487         if(cflag & PARENB) {
1488                 sEnParity(cp);
1489                 if(cflag & PARODD) {
1490                         sSetOddParity(cp);
1491                 } else {
1492                         sSetEvenParity(cp);
1493                 }
1494         }
1495         else {
1496                 sDisParity(cp);
1497         }
1498         if((cflag & CSIZE) == CS8) {
1499                 sSetData8(cp);
1500                 rp->rp_imask = 0xFF;
1501         } else {
1502                 sSetData7(cp);
1503                 rp->rp_imask = 0x7F;
1504         }
1505
1506         if(iflag & ISTRIP) {
1507                 rp->rp_imask &= 0x7F;
1508         }
1509
1510         if(cflag & CLOCAL) {
1511                 rp->rp_intmask &= ~DELTA_CD;
1512         } else {
1513                 rp->rp_intmask |= DELTA_CD;
1514         }
1515
1516         /* Put flow control stuff here */
1517
1518         if(cflag & CCTS_OFLOW) {
1519                 sEnCTSFlowCtl(cp);
1520         } else {
1521                 sDisCTSFlowCtl(cp);
1522         }
1523
1524         if(cflag & CRTS_IFLOW) {
1525                 rp->rp_rts_iflow = 1;
1526         } else {
1527                 rp->rp_rts_iflow = 0;
1528         }
1529
1530         if(cflag & CRTS_IFLOW) {
1531                 sEnRTSFlowCtl(cp);
1532         } else {
1533                 sDisRTSFlowCtl(cp);
1534         }
1535         rp_disc_optim(tp, t);
1536
1537         if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1538                 tp->t_state |= TS_CARR_ON;
1539                 wakeup(TSA_CARR_ON(tp));
1540         }
1541
1542 /*      tp->t_state |= TS_CAN_BYPASS_L_RINT;
1543         flags = rp->rp_channel.TxControl[3];
1544         if(flags & SET_DTR)
1545         else
1546         if(flags & SET_RTS)
1547         else
1548 */
1549         splx(oldspl);
1550
1551         return(0);
1552 }
1553
1554 static void
1555 rp_disc_optim(tp, t)
1556 struct  tty     *tp;
1557 struct  termios *t;
1558 {
1559         if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1560                 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1561                 &&(!(t->c_iflag & PARMRK)
1562                   ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1563                 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1564                 && linesw[tp->t_line].l_rint == ttyinput)
1565                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1566         else
1567                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1568 }
1569
1570 static void
1571 rpstart(tp)
1572         struct tty *tp;
1573 {
1574         struct rp_port  *rp;
1575         CHANNEL_t       *cp;
1576         struct  clist   *qp;
1577         int     unit, mynor, port, umynor;               /* SG */
1578         char    flags;
1579         int     spl, xmit_fifo_room;
1580         int     count, wcount;
1581
1582
1583    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1584         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1585         mynor = (port + umynor);                          /* SG */
1586         unit = minor_to_unit[mynor];
1587         rp = rp_addr(unit) + port;
1588         cp = &rp->rp_channel;
1589         flags = rp->rp_channel.TxControl[3];
1590         spl = spltty();
1591
1592         if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1593                 ttwwakeup(tp);
1594                 splx(spl);
1595                 return;
1596         }
1597         if(rp->rp_xmit_stopped) {
1598                 sEnTransmit(cp);
1599                 rp->rp_xmit_stopped = 0;
1600         }
1601         count = sGetTxCnt(cp);
1602
1603         if(tp->t_outq.c_cc == 0) {
1604                 if((tp->t_state & TS_BUSY) && (count == 0)) {
1605                         tp->t_state &= ~TS_BUSY;
1606                 }
1607                 ttwwakeup(tp);
1608                 splx(spl);
1609                 return;
1610         }
1611         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1612         qp = &tp->t_outq;
1613         if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1614                 tp->t_state |= TS_BUSY;
1615                 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1616                 wcount = count >> 1;
1617                 if ( wcount ) {
1618                         rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1619                 }
1620                 if ( count & 1 ) {
1621                         rp_writech1(cp, sGetTxRxDataIO(cp),
1622                                     ((unsigned char *)(rp->TxBuf))[(count-1)]);
1623                 }
1624         }
1625         rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1626
1627         ttwwakeup(tp);
1628         splx(spl);
1629 }
1630
1631 static
1632 void
1633 rpstop(tp, flag)
1634         struct tty *tp;
1635         int     flag;
1636 {
1637         struct rp_port  *rp;
1638         CHANNEL_t       *cp;
1639         int     unit, mynor, port, umynor;                  /* SG */
1640         int     spl;
1641
1642    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1643         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1644         mynor = (port + umynor);                          /* SG */
1645         unit = minor_to_unit[mynor];
1646         rp = rp_addr(unit) + port;
1647         cp = &rp->rp_channel;
1648
1649         spl = spltty();
1650
1651         if(tp->t_state & TS_BUSY) {
1652                 if((tp->t_state&TS_TTSTOP) == 0) {
1653                         sFlushTxFIFO(cp);
1654                 } else {
1655                         if(rp->rp_xmit_stopped == 0) {
1656                                 sDisTransmit(cp);
1657                                 rp->rp_xmit_stopped = 1;
1658                         }
1659                 }
1660         }
1661         splx(spl);
1662         rpstart(tp);
1663 }