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