]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rp/rp.c
dev: make some use of mallocarray(9).
[FreeBSD/FreeBSD.git] / sys / dev / rp / rp.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) Comtrol Corporation <support@comtrol.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted prodived that the follwoing conditions
9  * are met.
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notive, this list of conditions and the following disclainer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials prodided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *       This product includes software developed by Comtrol Corporation.
18  * 4. The name of Comtrol Corporation may not be used to endorse or 
19  *    promote products derived from this software without specific 
20  *    prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
26  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /* 
40  * rp.c - for RocketPort FreeBSD
41  */
42
43 #include "opt_compat.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/endian.h>
48 #include <sys/fcntl.h>
49 #include <sys/malloc.h>
50 #include <sys/serial.h>
51 #include <sys/tty.h>
52 #include <sys/conf.h>
53 #include <sys/kernel.h>
54 #include <machine/resource.h>
55 #include <machine/bus.h>
56 #include <sys/bus.h>
57 #include <sys/rman.h>
58
59 #define ROCKET_C
60 #include <dev/rp/rpreg.h>
61 #include <dev/rp/rpvar.h>
62
63 static const char RocketPortVersion[] = "3.02";
64
65 static Byte_t RData[RDATASIZE] =
66 {
67    0x00, 0x09, 0xf6, 0x82,
68    0x02, 0x09, 0x86, 0xfb,
69    0x04, 0x09, 0x00, 0x0a,
70    0x06, 0x09, 0x01, 0x0a,
71    0x08, 0x09, 0x8a, 0x13,
72    0x0a, 0x09, 0xc5, 0x11,
73    0x0c, 0x09, 0x86, 0x85,
74    0x0e, 0x09, 0x20, 0x0a,
75    0x10, 0x09, 0x21, 0x0a,
76    0x12, 0x09, 0x41, 0xff,
77    0x14, 0x09, 0x82, 0x00,
78    0x16, 0x09, 0x82, 0x7b,
79    0x18, 0x09, 0x8a, 0x7d,
80    0x1a, 0x09, 0x88, 0x81,
81    0x1c, 0x09, 0x86, 0x7a,
82    0x1e, 0x09, 0x84, 0x81,
83    0x20, 0x09, 0x82, 0x7c,
84    0x22, 0x09, 0x0a, 0x0a
85 };
86
87 static Byte_t RRegData[RREGDATASIZE]=
88 {
89    0x00, 0x09, 0xf6, 0x82,             /* 00: Stop Rx processor */
90    0x08, 0x09, 0x8a, 0x13,             /* 04: Tx software flow control */
91    0x0a, 0x09, 0xc5, 0x11,             /* 08: XON char */
92    0x0c, 0x09, 0x86, 0x85,             /* 0c: XANY */
93    0x12, 0x09, 0x41, 0xff,             /* 10: Rx mask char */
94    0x14, 0x09, 0x82, 0x00,             /* 14: Compare/Ignore #0 */
95    0x16, 0x09, 0x82, 0x7b,             /* 18: Compare #1 */
96    0x18, 0x09, 0x8a, 0x7d,             /* 1c: Compare #2 */
97    0x1a, 0x09, 0x88, 0x81,             /* 20: Interrupt #1 */
98    0x1c, 0x09, 0x86, 0x7a,             /* 24: Ignore/Replace #1 */
99    0x1e, 0x09, 0x84, 0x81,             /* 28: Interrupt #2 */
100    0x20, 0x09, 0x82, 0x7c,             /* 2c: Ignore/Replace #2 */
101    0x22, 0x09, 0x0a, 0x0a              /* 30: Rx FIFO Enable */
102 };
103
104 #if 0
105 /* IRQ number to MUDBAC register 2 mapping */
106 Byte_t sIRQMap[16] =
107 {
108    0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
109 };
110 #endif
111
112 Byte_t rp_sBitMapClrTbl[8] =
113 {
114    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
115 };
116
117 Byte_t rp_sBitMapSetTbl[8] =
118 {
119    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
120 };
121
122 static void rpfree(void *);
123
124 /***************************************************************************
125 Function: sReadAiopID
126 Purpose:  Read the AIOP idenfication number directly from an AIOP.
127 Call:     sReadAiopID(CtlP, aiop)
128           CONTROLLER_T *CtlP; Ptr to controller structure
129           int aiop: AIOP index
130 Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
131                  is replace by an identifying number.
132           Flag AIOPID_NULL if no valid AIOP is found
133 Warnings: No context switches are allowed while executing this function.
134
135 */
136 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
137 {
138    Byte_t AiopID;               /* ID byte from AIOP */
139
140    rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL);     /* reset AIOP */
141    rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
142    AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
143    if(AiopID == 0x06)
144       return(1);
145    else                                /* AIOP does not exist */
146       return(-1);
147 }
148
149 /***************************************************************************
150 Function: sReadAiopNumChan
151 Purpose:  Read the number of channels available in an AIOP directly from
152           an AIOP.
153 Call:     sReadAiopNumChan(CtlP, aiop)
154           CONTROLLER_T *CtlP; Ptr to controller structure
155           int aiop: AIOP index
156 Return:   int: The number of channels available
157 Comments: The number of channels is determined by write/reads from identical
158           offsets within the SRAM address spaces for channels 0 and 4.
159           If the channel 4 space is mirrored to channel 0 it is a 4 channel
160           AIOP, otherwise it is an 8 channel.
161 Warnings: No context switches are allowed while executing this function.
162 */
163 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
164 {
165    Word_t x, y;
166
167    rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
168    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0);        /* read from SRAM, chan 0 */
169    x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
170    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
171    y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
172    if(x != y)  /* if different must be 8 chan */
173       return(8);
174    else
175       return(4);
176 }
177
178 /***************************************************************************
179 Function: sInitChan
180 Purpose:  Initialization of a channel and channel structure
181 Call:     sInitChan(CtlP,ChP,AiopNum,ChanNum)
182           CONTROLLER_T *CtlP; Ptr to controller structure
183           CHANNEL_T *ChP; Ptr to channel structure
184           int AiopNum; AIOP number within controller
185           int ChanNum; Channel number within AIOP
186 Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
187                number exceeds number of channels available in AIOP.
188 Comments: This function must be called before a channel can be used.
189 Warnings: No range checking on any of the parameters is done.
190
191           No context switches are allowed while executing this function.
192 */
193 int sInitChan(  CONTROLLER_T *CtlP,
194                 CHANNEL_T *ChP,
195                 int AiopNum,
196                 int ChanNum)
197 {
198    int i, ChOff;
199    Byte_t *ChR;
200    static Byte_t R[4];
201
202    if(ChanNum >= CtlP->AiopNumChan[AiopNum])
203       return(FALSE);                   /* exceeds num chans in AIOP */
204
205    /* Channel, AIOP, and controller identifiers */
206    ChP->CtlP = CtlP;
207    ChP->ChanID = CtlP->AiopID[AiopNum];
208    ChP->AiopNum = AiopNum;
209    ChP->ChanNum = ChanNum;
210
211    /* Initialize the channel from the RData array */
212    for(i=0; i < RDATASIZE; i+=4)
213    {
214       R[0] = RData[i];
215       R[1] = RData[i+1] + 0x10 * ChanNum;
216       R[2] = RData[i+2];
217       R[3] = RData[i+3];
218       rp_writech4(ChP,_INDX_ADDR,le32dec(R));
219    }
220
221    ChR = ChP->R;
222    for(i=0; i < RREGDATASIZE; i+=4)
223    {
224       ChR[i] = RRegData[i];
225       ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
226       ChR[i+2] = RRegData[i+2];
227       ChR[i+3] = RRegData[i+3];
228    }
229
230    /* Indexed registers */
231    ChOff = (Word_t)ChanNum * 0x1000;
232
233    ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
234    ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
235    ChP->BaudDiv[2] = (Byte_t)BRD9600;
236    ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
237    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv));
238
239    ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
240    ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
241    ChP->TxControl[2] = 0;
242    ChP->TxControl[3] = 0;
243    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
244
245    ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
246    ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
247    ChP->RxControl[2] = 0;
248    ChP->RxControl[3] = 0;
249    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
250
251    ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
252    ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
253    ChP->TxEnables[2] = 0;
254    ChP->TxEnables[3] = 0;
255    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables));
256
257    ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
258    ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
259    ChP->TxCompare[2] = 0;
260    ChP->TxCompare[3] = 0;
261    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare));
262
263    ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
264    ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
265    ChP->TxReplace1[2] = 0;
266    ChP->TxReplace1[3] = 0;
267    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1));
268
269    ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
270    ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
271    ChP->TxReplace2[2] = 0;
272    ChP->TxReplace2[3] = 0;
273    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2));
274
275    ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
276    ChP->TxFIFO = ChOff + _TX_FIFO;
277
278    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
279    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
280    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
281    rp_writech2(ChP,_INDX_DATA,0);
282    ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
283    ChP->RxFIFO = ChOff + _RX_FIFO;
284
285    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
286    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
287    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
288    rp_writech2(ChP,_INDX_DATA,0);
289    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
290    rp_writech2(ChP,_INDX_DATA,0);
291    ChP->TxPrioCnt = ChOff + _TXP_CNT;
292    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
293    rp_writech1(ChP,_INDX_DATA,0);
294    ChP->TxPrioPtr = ChOff + _TXP_PNTR;
295    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
296    rp_writech1(ChP,_INDX_DATA,0);
297    ChP->TxPrioBuf = ChOff + _TXP_BUF;
298    sEnRxProcessor(ChP);                /* start the Rx processor */
299
300    return(TRUE);
301 }
302
303 /***************************************************************************
304 Function: sStopRxProcessor
305 Purpose:  Stop the receive processor from processing a channel.
306 Call:     sStopRxProcessor(ChP)
307           CHANNEL_T *ChP; Ptr to channel structure
308
309 Comments: The receive processor can be started again with sStartRxProcessor().
310           This function causes the receive processor to skip over the
311           stopped channel.  It does not stop it from processing other channels.
312
313 Warnings: No context switches are allowed while executing this function.
314
315           Do not leave the receive processor stopped for more than one
316           character time.
317
318           After calling this function a delay of 4 uS is required to ensure
319           that the receive processor is no longer processing this channel.
320 */
321 void sStopRxProcessor(CHANNEL_T *ChP)
322 {
323    Byte_t R[4];
324
325    R[0] = ChP->R[0];
326    R[1] = ChP->R[1];
327    R[2] = 0x0a;
328    R[3] = ChP->R[3];
329    rp_writech4(ChP,_INDX_ADDR,le32dec(R));
330 }
331
332 /***************************************************************************
333 Function: sFlushRxFIFO
334 Purpose:  Flush the Rx FIFO
335 Call:     sFlushRxFIFO(ChP)
336           CHANNEL_T *ChP; Ptr to channel structure
337 Return:   void
338 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
339           while it is being flushed the receive processor is stopped
340           and the transmitter is disabled.  After these operations a
341           4 uS delay is done before clearing the pointers to allow
342           the receive processor to stop.  These items are handled inside
343           this function.
344 Warnings: No context switches are allowed while executing this function.
345 */
346 void sFlushRxFIFO(CHANNEL_T *ChP)
347 {
348    int i;
349    Byte_t Ch;                   /* channel number within AIOP */
350    int RxFIFOEnabled;                  /* TRUE if Rx FIFO enabled */
351
352    if(sGetRxCnt(ChP) == 0)             /* Rx FIFO empty */
353       return;                          /* don't need to flush */
354
355    RxFIFOEnabled = FALSE;
356    if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
357    {
358       RxFIFOEnabled = TRUE;
359       sDisRxFIFO(ChP);                 /* disable it */
360       for(i=0; i < 2000/200; i++)       /* delay 2 uS to allow proc to disable FIFO*/
361          rp_readch1(ChP,_INT_CHAN);             /* depends on bus i/o timing */
362    }
363    sGetChanStatus(ChP);          /* clear any pending Rx errors in chan stat */
364    Ch = (Byte_t)sGetChanNum(ChP);
365    rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
366    rp_writech1(ChP,_CMD_REG,Ch);                       /* remove reset Rx FIFO count */
367    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
368    rp_writech2(ChP,_INDX_DATA,0);
369    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
370    rp_writech2(ChP,_INDX_DATA,0);
371    if(RxFIFOEnabled)
372       sEnRxFIFO(ChP);                  /* enable Rx FIFO */
373 }
374
375 /***************************************************************************
376 Function: sFlushTxFIFO
377 Purpose:  Flush the Tx FIFO
378 Call:     sFlushTxFIFO(ChP)
379           CHANNEL_T *ChP; Ptr to channel structure
380 Return:   void
381 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
382           while it is being flushed the receive processor is stopped
383           and the transmitter is disabled.  After these operations a
384           4 uS delay is done before clearing the pointers to allow
385           the receive processor to stop.  These items are handled inside
386           this function.
387 Warnings: No context switches are allowed while executing this function.
388 */
389 void sFlushTxFIFO(CHANNEL_T *ChP)
390 {
391    int i;
392    Byte_t Ch;                   /* channel number within AIOP */
393    int TxEnabled;                      /* TRUE if transmitter enabled */
394
395    if(sGetTxCnt(ChP) == 0)             /* Tx FIFO empty */
396       return;                          /* don't need to flush */
397
398    TxEnabled = FALSE;
399    if(ChP->TxControl[3] & TX_ENABLE)
400    {
401       TxEnabled = TRUE;
402       sDisTransmit(ChP);               /* disable transmitter */
403    }
404    sStopRxProcessor(ChP);              /* stop Rx processor */
405    for(i = 0; i < 4000/200; i++)         /* delay 4 uS to allow proc to stop */
406       rp_readch1(ChP,_INT_CHAN);        /* depends on bus i/o timing */
407    Ch = (Byte_t)sGetChanNum(ChP);
408    rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT);     /* apply reset Tx FIFO count */
409    rp_writech1(ChP,_CMD_REG,Ch);                       /* remove reset Tx FIFO count */
410    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
411    rp_writech2(ChP,_INDX_DATA,0);
412    if(TxEnabled)
413       sEnTransmit(ChP);                /* enable transmitter */
414    sStartRxProcessor(ChP);             /* restart Rx processor */
415 }
416
417 /***************************************************************************
418 Function: sWriteTxPrioByte
419 Purpose:  Write a byte of priority transmit data to a channel
420 Call:     sWriteTxPrioByte(ChP,Data)
421           CHANNEL_T *ChP; Ptr to channel structure
422           Byte_t Data; The transmit data byte
423
424 Return:   int: 1 if the bytes is successfully written, otherwise 0.
425
426 Comments: The priority byte is transmitted before any data in the Tx FIFO.
427
428 Warnings: No context switches are allowed while executing this function.
429 */
430 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
431 {
432    Byte_t DWBuf[4];             /* buffer for double word writes */
433
434    if(sGetTxCnt(ChP) > 1)              /* write it to Tx priority buffer */
435    {
436       rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
437       if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
438          return(0);                    /* nothing sent */
439
440       le16enc(DWBuf,ChP->TxPrioBuf);   /* data byte address */
441
442       DWBuf[2] = Data;                 /* data byte value */
443       DWBuf[3] = 0;                    /* priority buffer pointer */
444       rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
445
446       le16enc(DWBuf,ChP->TxPrioCnt);   /* Tx priority count address */
447
448       DWBuf[2] = PRI_PEND + 1;         /* indicate 1 byte pending */
449       DWBuf[3] = 0;                    /* priority buffer pointer */
450       rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
451    }
452    else                                /* write it to Tx FIFO */
453    {
454       sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
455    }
456    return(1);                          /* 1 byte sent */
457 }
458
459 /***************************************************************************
460 Function: sEnInterrupts
461 Purpose:  Enable one or more interrupts for a channel
462 Call:     sEnInterrupts(ChP,Flags)
463           CHANNEL_T *ChP; Ptr to channel structure
464           Word_t Flags: Interrupt enable flags, can be any combination
465              of the following flags:
466                 TXINT_EN:   Interrupt on Tx FIFO empty
467                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
468                             sSetRxTrigger())
469                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
470                 MCINT_EN:   Interrupt on modem input change
471                 CHANINT_EN: Allow channel interrupt signal to the AIOP's
472                             Interrupt Channel Register.
473 Return:   void
474 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
475           enabled.  If an interrupt enable flag is not set in Flags, that
476           interrupt will not be changed.  Interrupts can be disabled with
477           function sDisInterrupts().
478
479           This function sets the appropriate bit for the channel in the AIOP's
480           Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
481           this channel's bit to be set in the AIOP's Interrupt Channel Register.
482
483           Interrupts must also be globally enabled before channel interrupts
484           will be passed on to the host.  This is done with function
485           sEnGlobalInt().
486
487           In some cases it may be desirable to disable interrupts globally but
488           enable channel interrupts.  This would allow the global interrupt
489           status register to be used to determine which AIOPs need service.
490 */
491 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
492 {
493    Byte_t Mask;                 /* Interrupt Mask Register */
494
495    ChP->RxControl[2] |=
496       ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
497
498    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
499
500    ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
501
502    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
503
504    if(Flags & CHANINT_EN)
505    {
506       Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
507       rp_writech1(ChP,_INT_MASK,Mask);
508    }
509 }
510
511 /***************************************************************************
512 Function: sDisInterrupts
513 Purpose:  Disable one or more interrupts for a channel
514 Call:     sDisInterrupts(ChP,Flags)
515           CHANNEL_T *ChP; Ptr to channel structure
516           Word_t Flags: Interrupt flags, can be any combination
517              of the following flags:
518                 TXINT_EN:   Interrupt on Tx FIFO empty
519                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
520                             sSetRxTrigger())
521                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
522                 MCINT_EN:   Interrupt on modem input change
523                 CHANINT_EN: Disable channel interrupt signal to the
524                             AIOP's Interrupt Channel Register.
525 Return:   void
526 Comments: If an interrupt flag is set in Flags, that interrupt will be
527           disabled.  If an interrupt flag is not set in Flags, that
528           interrupt will not be changed.  Interrupts can be enabled with
529           function sEnInterrupts().
530
531           This function clears the appropriate bit for the channel in the AIOP's
532           Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
533           this channel's bit from being set in the AIOP's Interrupt Channel
534           Register.
535 */
536 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
537 {
538    Byte_t Mask;                 /* Interrupt Mask Register */
539
540    ChP->RxControl[2] &=
541          ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
542    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
543    ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
544    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
545
546    if(Flags & CHANINT_EN)
547    {
548       Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
549       rp_writech1(ChP,_INT_MASK,Mask);
550    }
551 }
552
553 /*********************************************************************
554   Begin FreeBsd-specific driver code
555 **********************************************************************/
556
557 #define POLL_INTERVAL           (hz / 100)
558
559 #define RP_ISMULTIPORT(dev)     ((dev)->id_flags & 0x1)
560 #define RP_MPMASTER(dev)        (((dev)->id_flags >> 8) & 0xff)
561 #define RP_NOTAST4(dev)         ((dev)->id_flags & 0x04)
562
563 /*
564  * The top-level routines begin here
565  */
566
567 static  void    rpclose(struct tty *tp);
568 static  void    rphardclose(struct tty *tp);
569 static  int     rpmodem(struct tty *, int, int);
570 static  int     rpparam(struct tty *, struct termios *);
571 static  void    rpstart(struct tty *);
572 static  int     rpioctl(struct tty *, u_long, caddr_t, struct thread *);
573 static  int     rpopen(struct tty *);
574
575 static void rp_do_receive(struct rp_port *rp, struct tty *tp,
576                         CHANNEL_t *cp, unsigned int ChanStatus)
577 {
578         unsigned        int     CharNStat;
579         int     ToRecv, ch, err = 0;
580
581         ToRecv = sGetRxCnt(cp);
582         if(ToRecv == 0)
583                 return;
584
585 /*      If status indicates there are errored characters in the
586         FIFO, then enter status mode (a word in FIFO holds
587         characters and status)
588 */
589
590         if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
591                 if(!(ChanStatus & STATMODE)) {
592                         ChanStatus |= STATMODE;
593                         sEnRxStatusMode(cp);
594                 }
595         }
596 /*
597         if we previously entered status mode then read down the
598         FIFO one word at a time, pulling apart the character and
599         the status. Update error counters depending on status.
600 */
601         tty_lock(tp);
602         if(ChanStatus & STATMODE) {
603                 while(ToRecv) {
604                         CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
605                         ch = CharNStat & 0xff;
606
607                         if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
608                                 err |= TRE_FRAMING;
609                         else if (CharNStat & STMPARITYH)
610                                 err |= TRE_PARITY;
611                         else if (CharNStat & STMRCVROVRH) {
612                                 rp->rp_overflows++;
613                                 err |= TRE_OVERRUN;
614                         }
615
616                         ttydisc_rint(tp, ch, err);
617                         ToRecv--;
618                 }
619 /*
620         After emtying FIFO in status mode, turn off status mode
621 */
622
623                 if(sGetRxCnt(cp) == 0) {
624                         sDisRxStatusMode(cp);
625                 }
626         } else {
627                 ToRecv = sGetRxCnt(cp);
628                 while (ToRecv) {
629                         ch = rp_readch1(cp,sGetTxRxDataIO(cp));
630                         ttydisc_rint(tp, ch & 0xff, err);
631                         ToRecv--;
632                 }
633         }
634         ttydisc_rint_done(tp);
635         tty_unlock(tp);
636 }
637
638 static void rp_handle_port(struct rp_port *rp)
639 {
640         CHANNEL_t       *cp;
641         struct  tty     *tp;
642         unsigned        int     IntMask, ChanStatus;
643
644         if(!rp)
645                 return;
646
647         cp = &rp->rp_channel;
648         tp = rp->rp_tty;
649         IntMask = sGetChanIntID(cp);
650         IntMask = IntMask & rp->rp_intmask;
651         ChanStatus = sGetChanStatus(cp);
652         if(IntMask & RXF_TRIG)
653                 rp_do_receive(rp, tp, cp, ChanStatus);
654         if(IntMask & DELTA_CD) {
655                 if(ChanStatus & CD_ACT) {
656                         (void)ttydisc_modem(tp, 1);
657                 } else {
658                         (void)ttydisc_modem(tp, 0);
659                 }
660         }
661 /*      oldcts = rp->rp_cts;
662         rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
663         if(oldcts != rp->rp_cts) {
664                 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
665         }
666 */
667 }
668
669 static void rp_do_poll(void *arg)
670 {
671         CONTROLLER_t    *ctl;
672         struct rp_port  *rp;
673         struct tty      *tp;
674         int     count;
675         unsigned char   CtlMask, AiopMask;
676
677         rp = arg;
678         tp = rp->rp_tty;
679         tty_lock_assert(tp, MA_OWNED);
680         ctl = rp->rp_ctlp;
681         CtlMask = ctl->ctlmask(ctl);
682         if (CtlMask & (1 << rp->rp_aiop)) {
683                 AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop);
684                 if (AiopMask & (1 << rp->rp_chan)) {
685                         rp_handle_port(rp);
686                 }
687         }
688
689         count = sGetTxCnt(&rp->rp_channel);
690         if (count >= 0  && (count <= rp->rp_restart)) {
691                 rpstart(tp);
692         }
693         callout_schedule(&rp->rp_timer, POLL_INTERVAL);
694 }
695
696 static struct ttydevsw rp_tty_class = {
697         .tsw_flags      = TF_INITLOCK|TF_CALLOUT,
698         .tsw_open       = rpopen,
699         .tsw_close      = rpclose,
700         .tsw_outwakeup  = rpstart,
701         .tsw_ioctl      = rpioctl,
702         .tsw_param      = rpparam,
703         .tsw_modem      = rpmodem,
704         .tsw_free       = rpfree,
705 };
706
707
708 static void
709 rpfree(void *softc)
710 {
711         struct  rp_port *rp = softc;
712         CONTROLLER_t *ctlp = rp->rp_ctlp;
713
714         atomic_subtract_32(&ctlp->free, 1);
715 }
716
717 int
718 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
719 {
720         int     unit;
721         int     num_chan;
722         int     aiop, chan, port;
723         int     ChanStatus;
724         int     retval;
725         struct  rp_port *rp;
726         struct tty *tp;
727
728         unit = device_get_unit(ctlp->dev);
729
730         printf("RocketPort%d (Version %s) %d ports.\n", unit,
731                 RocketPortVersion, num_ports);
732
733         ctlp->num_ports = num_ports;
734         ctlp->rp = rp = (struct rp_port *)
735                 mallocarray(num_ports, sizeof(struct rp_port), M_DEVBUF,
736                     M_NOWAIT | M_ZERO);
737         if (rp == NULL) {
738                 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
739                 retval = ENOMEM;
740                 goto nogo;
741         }
742
743         port = 0;
744         for(aiop=0; aiop < num_aiops; aiop++) {
745                 num_chan = sGetAiopNumChan(ctlp, aiop);
746                 for(chan=0; chan < num_chan; chan++, port++, rp++) {
747                         rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
748                         callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
749                         rp->rp_port = port;
750                         rp->rp_ctlp = ctlp;
751                         rp->rp_unit = unit;
752                         rp->rp_chan = chan;
753                         rp->rp_aiop = aiop;
754
755                         rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
756                                 DELTA_CD | DELTA_CTS | DELTA_DSR;
757 #ifdef notdef
758                         ChanStatus = sGetChanStatus(&rp->rp_channel);
759 #endif /* notdef */
760                         if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
761                                 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
762                                               unit, aiop, chan);
763                                 retval = ENXIO;
764                                 goto nogo;
765                         }
766                         ChanStatus = sGetChanStatus(&rp->rp_channel);
767                         rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
768                         tty_makedev(tp, NULL, "R%r%r", unit, port);
769                 }
770         }
771
772         mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
773         ctlp->hwmtx_init = 1;
774         return (0);
775
776 nogo:
777         rp_releaseresource(ctlp);
778
779         return (retval);
780 }
781
782 void
783 rp_releaseresource(CONTROLLER_t *ctlp)
784 {
785         struct  rp_port *rp;
786         int i;
787
788         if (ctlp->rp != NULL) {
789                 for (i = 0; i < ctlp->num_ports; i++) {
790                         rp = ctlp->rp + i;
791                         atomic_add_32(&ctlp->free, 1);
792                         tty_lock(rp->rp_tty);
793                         tty_rel_gone(rp->rp_tty);
794                 }
795                 free(ctlp->rp, M_DEVBUF);
796                 ctlp->rp = NULL;
797         }
798
799         while (ctlp->free != 0) {
800                 pause("rpwt", hz / 10);
801         }
802
803         if (ctlp->hwmtx_init)
804                 mtx_destroy(&ctlp->hwmtx);
805 }
806
807 static int
808 rpopen(struct tty *tp)
809 {
810         struct  rp_port *rp;
811         int     flags;
812         unsigned int    IntMask, ChanStatus;
813
814         rp = tty_softc(tp);
815
816         flags = 0;
817         flags |= SET_RTS;
818         flags |= SET_DTR;
819         rp->rp_channel.TxControl[3] =
820                 ((rp->rp_channel.TxControl[3]
821                 & ~(SET_RTS | SET_DTR)) | flags);
822         rp_writech4(&rp->rp_channel,_INDX_ADDR,
823                 le32dec(rp->rp_channel.TxControl));
824         sSetRxTrigger(&rp->rp_channel, TRIG_1);
825         sDisRxStatusMode(&rp->rp_channel);
826         sFlushRxFIFO(&rp->rp_channel);
827         sFlushTxFIFO(&rp->rp_channel);
828
829         sEnInterrupts(&rp->rp_channel,
830                 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
831         sSetRxTrigger(&rp->rp_channel, TRIG_1);
832
833         sDisRxStatusMode(&rp->rp_channel);
834         sClrTxXOFF(&rp->rp_channel);
835
836 /*      sDisRTSFlowCtl(&rp->rp_channel);
837         sDisCTSFlowCtl(&rp->rp_channel);
838 */
839         sDisTxSoftFlowCtl(&rp->rp_channel);
840
841         sStartRxProcessor(&rp->rp_channel);
842
843         sEnRxFIFO(&rp->rp_channel);
844         sEnTransmit(&rp->rp_channel);
845
846 /*      sSetDTR(&rp->rp_channel);
847         sSetRTS(&rp->rp_channel);
848 */
849
850         IntMask = sGetChanIntID(&rp->rp_channel);
851         IntMask = IntMask & rp->rp_intmask;
852         ChanStatus = sGetChanStatus(&rp->rp_channel);
853
854         callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
855
856         device_busy(rp->rp_ctlp->dev);
857         return(0);
858 }
859
860 static void
861 rpclose(struct tty *tp)
862 {
863         struct  rp_port *rp;
864
865         rp = tty_softc(tp);
866         callout_stop(&rp->rp_timer);
867         rphardclose(tp);
868         device_unbusy(rp->rp_ctlp->dev);
869 }
870
871 static void
872 rphardclose(struct tty *tp)
873 {
874         struct  rp_port *rp;
875         CHANNEL_t       *cp;
876
877         rp = tty_softc(tp);
878         cp = &rp->rp_channel;
879
880         sFlushRxFIFO(cp);
881         sFlushTxFIFO(cp);
882         sDisTransmit(cp);
883         sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
884         sDisRTSFlowCtl(cp);
885         sDisCTSFlowCtl(cp);
886         sDisTxSoftFlowCtl(cp);
887         sClrTxXOFF(cp);
888
889 #ifdef DJA
890         if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
891                 sClrDTR(cp);
892         }
893         if(ISCALLOUT(tp->t_dev)) {
894                 sClrDTR(cp);
895         }
896         tp->t_actout = FALSE;
897         wakeup(&tp->t_actout);
898         wakeup(TSA_CARR_ON(tp));
899 #endif /* DJA */
900 }
901
902 static int
903 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
904 {
905         struct rp_port  *rp;
906
907         rp = tty_softc(tp);
908         switch (cmd) {
909         case TIOCSBRK:
910                 sSendBreak(&rp->rp_channel);
911                 return (0);
912         case TIOCCBRK:
913                 sClrBreak(&rp->rp_channel);
914                 return (0);
915         default:
916                 return ENOIOCTL;
917         }
918 }
919
920 static int
921 rpmodem(struct tty *tp, int sigon, int sigoff)
922 {
923         struct rp_port  *rp;
924         int i, j, k;
925
926         rp = tty_softc(tp);
927         if (sigon != 0 || sigoff != 0) {
928                 i = j = 0;
929                 if (sigon & SER_DTR)
930                         i = SET_DTR;
931                 if (sigoff & SER_DTR)
932                         j = SET_DTR;
933                 if (sigon & SER_RTS)
934                         i = SET_RTS;
935                 if (sigoff & SER_RTS)
936                         j = SET_RTS;
937                 rp->rp_channel.TxControl[3] &= ~i;
938                 rp->rp_channel.TxControl[3] |= j;
939                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
940                         le32dec(rp->rp_channel.TxControl));
941         } else {
942                 i = sGetChanStatusLo(&rp->rp_channel);
943                 j = rp->rp_channel.TxControl[3];
944                 k = 0;
945                 if (j & SET_DTR)
946                         k |= SER_DTR;
947                 if (j & SET_RTS)
948                         k |= SER_RTS;
949                 if (i & CD_ACT)
950                         k |= SER_DCD;
951                 if (i & DSR_ACT)
952                         k |= SER_DSR;
953                 if (i & CTS_ACT)
954                         k |= SER_CTS;
955                 return(k);
956         }
957         return (0);
958 }
959
960 static struct
961 {
962         int baud;
963         int conversion;
964 } baud_table[] = {
965         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
966         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
967         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
968         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
969         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
970         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
971                                 {B57600, BRD57600},     {B76800, BRD76800},
972         {B115200, BRD115200},   {B230400, BRD230400},
973         {-1,    -1}
974 };
975
976 static int rp_convert_baud(int baud) {
977         int i;
978
979         for (i = 0; baud_table[i].baud >= 0; i++) {
980                 if (baud_table[i].baud == baud)
981                         break;
982         }
983
984         return baud_table[i].conversion;
985 }
986
987 static int
988 rpparam(tp, t)
989         struct tty *tp;
990         struct termios *t;
991 {
992         struct rp_port  *rp;
993         CHANNEL_t       *cp;
994         int     cflag, iflag, oflag, lflag;
995         int     ospeed;
996 #ifdef RPCLOCAL
997         int     devshift;
998 #endif
999
1000         rp = tty_softc(tp);
1001         cp = &rp->rp_channel;
1002
1003         cflag = t->c_cflag;
1004 #ifdef RPCLOCAL
1005         devshift = umynor / 32;
1006         devshift = 1 << devshift;
1007         if ( devshift & RPCLOCAL ) {
1008                 cflag |= CLOCAL;
1009         }
1010 #endif
1011         iflag = t->c_iflag;
1012         oflag = t->c_oflag;
1013         lflag = t->c_lflag;
1014
1015         ospeed = rp_convert_baud(t->c_ispeed);
1016         if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1017                 return(EINVAL);
1018
1019         if(t->c_ospeed == 0) {
1020                 sClrDTR(cp);
1021                 return(0);
1022         }
1023         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1024
1025         /* Set baud rate ----- we only pay attention to ispeed */
1026         sSetDTR(cp);
1027         sSetRTS(cp);
1028         sSetBaud(cp, ospeed);
1029
1030         if(cflag & CSTOPB) {
1031                 sSetStop2(cp);
1032         } else {
1033                 sSetStop1(cp);
1034         }
1035
1036         if(cflag & PARENB) {
1037                 sEnParity(cp);
1038                 if(cflag & PARODD) {
1039                         sSetOddParity(cp);
1040                 } else {
1041                         sSetEvenParity(cp);
1042                 }
1043         }
1044         else {
1045                 sDisParity(cp);
1046         }
1047         if((cflag & CSIZE) == CS8) {
1048                 sSetData8(cp);
1049                 rp->rp_imask = 0xFF;
1050         } else {
1051                 sSetData7(cp);
1052                 rp->rp_imask = 0x7F;
1053         }
1054
1055         if(iflag & ISTRIP) {
1056                 rp->rp_imask &= 0x7F;
1057         }
1058
1059         if(cflag & CLOCAL) {
1060                 rp->rp_intmask &= ~DELTA_CD;
1061         } else {
1062                 rp->rp_intmask |= DELTA_CD;
1063         }
1064
1065         /* Put flow control stuff here */
1066
1067         if(cflag & CCTS_OFLOW) {
1068                 sEnCTSFlowCtl(cp);
1069         } else {
1070                 sDisCTSFlowCtl(cp);
1071         }
1072
1073         if(cflag & CRTS_IFLOW) {
1074                 rp->rp_rts_iflow = 1;
1075         } else {
1076                 rp->rp_rts_iflow = 0;
1077         }
1078
1079         if(cflag & CRTS_IFLOW) {
1080                 sEnRTSFlowCtl(cp);
1081         } else {
1082                 sDisRTSFlowCtl(cp);
1083         }
1084
1085         return(0);
1086 }
1087
1088 static void
1089 rpstart(struct tty *tp)
1090 {
1091         struct rp_port  *rp;
1092         CHANNEL_t       *cp;
1093         char    flags;
1094         int     xmit_fifo_room;
1095         int     i, count, wcount;
1096
1097         rp = tty_softc(tp);
1098         cp = &rp->rp_channel;
1099         flags = rp->rp_channel.TxControl[3];
1100
1101         if(rp->rp_xmit_stopped) {
1102                 sEnTransmit(cp);
1103                 rp->rp_xmit_stopped = 0;
1104         }
1105
1106         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1107         count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1108         if(xmit_fifo_room > 0) {
1109                 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1110                         rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1111                 }
1112                 if ( count & 1 ) {
1113                         rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);
1114                 }
1115         }
1116 }