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