]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rp/rp.c
MFV r329766: 8962 zdb should work on non-idle pools
[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                 malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
736         if (rp == NULL) {
737                 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
738                 retval = ENOMEM;
739                 goto nogo;
740         }
741
742         port = 0;
743         for(aiop=0; aiop < num_aiops; aiop++) {
744                 num_chan = sGetAiopNumChan(ctlp, aiop);
745                 for(chan=0; chan < num_chan; chan++, port++, rp++) {
746                         rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
747                         callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
748                         rp->rp_port = port;
749                         rp->rp_ctlp = ctlp;
750                         rp->rp_unit = unit;
751                         rp->rp_chan = chan;
752                         rp->rp_aiop = aiop;
753
754                         rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
755                                 DELTA_CD | DELTA_CTS | DELTA_DSR;
756 #ifdef notdef
757                         ChanStatus = sGetChanStatus(&rp->rp_channel);
758 #endif /* notdef */
759                         if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
760                                 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
761                                               unit, aiop, chan);
762                                 retval = ENXIO;
763                                 goto nogo;
764                         }
765                         ChanStatus = sGetChanStatus(&rp->rp_channel);
766                         rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
767                         tty_makedev(tp, NULL, "R%r%r", unit, port);
768                 }
769         }
770
771         mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
772         ctlp->hwmtx_init = 1;
773         return (0);
774
775 nogo:
776         rp_releaseresource(ctlp);
777
778         return (retval);
779 }
780
781 void
782 rp_releaseresource(CONTROLLER_t *ctlp)
783 {
784         struct  rp_port *rp;
785         int i;
786
787         if (ctlp->rp != NULL) {
788                 for (i = 0; i < ctlp->num_ports; i++) {
789                         rp = ctlp->rp + i;
790                         atomic_add_32(&ctlp->free, 1);
791                         tty_lock(rp->rp_tty);
792                         tty_rel_gone(rp->rp_tty);
793                 }
794                 free(ctlp->rp, M_DEVBUF);
795                 ctlp->rp = NULL;
796         }
797
798         while (ctlp->free != 0) {
799                 pause("rpwt", hz / 10);
800         }
801
802         if (ctlp->hwmtx_init)
803                 mtx_destroy(&ctlp->hwmtx);
804 }
805
806 static int
807 rpopen(struct tty *tp)
808 {
809         struct  rp_port *rp;
810         int     flags;
811         unsigned int    IntMask, ChanStatus;
812
813         rp = tty_softc(tp);
814
815         flags = 0;
816         flags |= SET_RTS;
817         flags |= SET_DTR;
818         rp->rp_channel.TxControl[3] =
819                 ((rp->rp_channel.TxControl[3]
820                 & ~(SET_RTS | SET_DTR)) | flags);
821         rp_writech4(&rp->rp_channel,_INDX_ADDR,
822                 le32dec(rp->rp_channel.TxControl));
823         sSetRxTrigger(&rp->rp_channel, TRIG_1);
824         sDisRxStatusMode(&rp->rp_channel);
825         sFlushRxFIFO(&rp->rp_channel);
826         sFlushTxFIFO(&rp->rp_channel);
827
828         sEnInterrupts(&rp->rp_channel,
829                 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
830         sSetRxTrigger(&rp->rp_channel, TRIG_1);
831
832         sDisRxStatusMode(&rp->rp_channel);
833         sClrTxXOFF(&rp->rp_channel);
834
835 /*      sDisRTSFlowCtl(&rp->rp_channel);
836         sDisCTSFlowCtl(&rp->rp_channel);
837 */
838         sDisTxSoftFlowCtl(&rp->rp_channel);
839
840         sStartRxProcessor(&rp->rp_channel);
841
842         sEnRxFIFO(&rp->rp_channel);
843         sEnTransmit(&rp->rp_channel);
844
845 /*      sSetDTR(&rp->rp_channel);
846         sSetRTS(&rp->rp_channel);
847 */
848
849         IntMask = sGetChanIntID(&rp->rp_channel);
850         IntMask = IntMask & rp->rp_intmask;
851         ChanStatus = sGetChanStatus(&rp->rp_channel);
852
853         callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
854
855         device_busy(rp->rp_ctlp->dev);
856         return(0);
857 }
858
859 static void
860 rpclose(struct tty *tp)
861 {
862         struct  rp_port *rp;
863
864         rp = tty_softc(tp);
865         callout_stop(&rp->rp_timer);
866         rphardclose(tp);
867         device_unbusy(rp->rp_ctlp->dev);
868 }
869
870 static void
871 rphardclose(struct tty *tp)
872 {
873         struct  rp_port *rp;
874         CHANNEL_t       *cp;
875
876         rp = tty_softc(tp);
877         cp = &rp->rp_channel;
878
879         sFlushRxFIFO(cp);
880         sFlushTxFIFO(cp);
881         sDisTransmit(cp);
882         sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
883         sDisRTSFlowCtl(cp);
884         sDisCTSFlowCtl(cp);
885         sDisTxSoftFlowCtl(cp);
886         sClrTxXOFF(cp);
887
888 #ifdef DJA
889         if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
890                 sClrDTR(cp);
891         }
892         if(ISCALLOUT(tp->t_dev)) {
893                 sClrDTR(cp);
894         }
895         tp->t_actout = FALSE;
896         wakeup(&tp->t_actout);
897         wakeup(TSA_CARR_ON(tp));
898 #endif /* DJA */
899 }
900
901 static int
902 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
903 {
904         struct rp_port  *rp;
905
906         rp = tty_softc(tp);
907         switch (cmd) {
908         case TIOCSBRK:
909                 sSendBreak(&rp->rp_channel);
910                 return (0);
911         case TIOCCBRK:
912                 sClrBreak(&rp->rp_channel);
913                 return (0);
914         default:
915                 return ENOIOCTL;
916         }
917 }
918
919 static int
920 rpmodem(struct tty *tp, int sigon, int sigoff)
921 {
922         struct rp_port  *rp;
923         int i, j, k;
924
925         rp = tty_softc(tp);
926         if (sigon != 0 || sigoff != 0) {
927                 i = j = 0;
928                 if (sigon & SER_DTR)
929                         i = SET_DTR;
930                 if (sigoff & SER_DTR)
931                         j = SET_DTR;
932                 if (sigon & SER_RTS)
933                         i = SET_RTS;
934                 if (sigoff & SER_RTS)
935                         j = SET_RTS;
936                 rp->rp_channel.TxControl[3] &= ~i;
937                 rp->rp_channel.TxControl[3] |= j;
938                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
939                         le32dec(rp->rp_channel.TxControl));
940         } else {
941                 i = sGetChanStatusLo(&rp->rp_channel);
942                 j = rp->rp_channel.TxControl[3];
943                 k = 0;
944                 if (j & SET_DTR)
945                         k |= SER_DTR;
946                 if (j & SET_RTS)
947                         k |= SER_RTS;
948                 if (i & CD_ACT)
949                         k |= SER_DCD;
950                 if (i & DSR_ACT)
951                         k |= SER_DSR;
952                 if (i & CTS_ACT)
953                         k |= SER_CTS;
954                 return(k);
955         }
956         return (0);
957 }
958
959 static struct
960 {
961         int baud;
962         int conversion;
963 } baud_table[] = {
964         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
965         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
966         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
967         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
968         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
969         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
970                                 {B57600, BRD57600},     {B76800, BRD76800},
971         {B115200, BRD115200},   {B230400, BRD230400},
972         {-1,    -1}
973 };
974
975 static int rp_convert_baud(int baud) {
976         int i;
977
978         for (i = 0; baud_table[i].baud >= 0; i++) {
979                 if (baud_table[i].baud == baud)
980                         break;
981         }
982
983         return baud_table[i].conversion;
984 }
985
986 static int
987 rpparam(tp, t)
988         struct tty *tp;
989         struct termios *t;
990 {
991         struct rp_port  *rp;
992         CHANNEL_t       *cp;
993         int     cflag, iflag, oflag, lflag;
994         int     ospeed;
995 #ifdef RPCLOCAL
996         int     devshift;
997 #endif
998
999         rp = tty_softc(tp);
1000         cp = &rp->rp_channel;
1001
1002         cflag = t->c_cflag;
1003 #ifdef RPCLOCAL
1004         devshift = umynor / 32;
1005         devshift = 1 << devshift;
1006         if ( devshift & RPCLOCAL ) {
1007                 cflag |= CLOCAL;
1008         }
1009 #endif
1010         iflag = t->c_iflag;
1011         oflag = t->c_oflag;
1012         lflag = t->c_lflag;
1013
1014         ospeed = rp_convert_baud(t->c_ispeed);
1015         if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1016                 return(EINVAL);
1017
1018         if(t->c_ospeed == 0) {
1019                 sClrDTR(cp);
1020                 return(0);
1021         }
1022         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1023
1024         /* Set baud rate ----- we only pay attention to ispeed */
1025         sSetDTR(cp);
1026         sSetRTS(cp);
1027         sSetBaud(cp, ospeed);
1028
1029         if(cflag & CSTOPB) {
1030                 sSetStop2(cp);
1031         } else {
1032                 sSetStop1(cp);
1033         }
1034
1035         if(cflag & PARENB) {
1036                 sEnParity(cp);
1037                 if(cflag & PARODD) {
1038                         sSetOddParity(cp);
1039                 } else {
1040                         sSetEvenParity(cp);
1041                 }
1042         }
1043         else {
1044                 sDisParity(cp);
1045         }
1046         if((cflag & CSIZE) == CS8) {
1047                 sSetData8(cp);
1048                 rp->rp_imask = 0xFF;
1049         } else {
1050                 sSetData7(cp);
1051                 rp->rp_imask = 0x7F;
1052         }
1053
1054         if(iflag & ISTRIP) {
1055                 rp->rp_imask &= 0x7F;
1056         }
1057
1058         if(cflag & CLOCAL) {
1059                 rp->rp_intmask &= ~DELTA_CD;
1060         } else {
1061                 rp->rp_intmask |= DELTA_CD;
1062         }
1063
1064         /* Put flow control stuff here */
1065
1066         if(cflag & CCTS_OFLOW) {
1067                 sEnCTSFlowCtl(cp);
1068         } else {
1069                 sDisCTSFlowCtl(cp);
1070         }
1071
1072         if(cflag & CRTS_IFLOW) {
1073                 rp->rp_rts_iflow = 1;
1074         } else {
1075                 rp->rp_rts_iflow = 0;
1076         }
1077
1078         if(cflag & CRTS_IFLOW) {
1079                 sEnRTSFlowCtl(cp);
1080         } else {
1081                 sDisRTSFlowCtl(cp);
1082         }
1083
1084         return(0);
1085 }
1086
1087 static void
1088 rpstart(struct tty *tp)
1089 {
1090         struct rp_port  *rp;
1091         CHANNEL_t       *cp;
1092         char    flags;
1093         int     xmit_fifo_room;
1094         int     i, count, wcount;
1095
1096         rp = tty_softc(tp);
1097         cp = &rp->rp_channel;
1098         flags = rp->rp_channel.TxControl[3];
1099
1100         if(rp->rp_xmit_stopped) {
1101                 sEnTransmit(cp);
1102                 rp->rp_xmit_stopped = 0;
1103         }
1104
1105         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1106         count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1107         if(xmit_fifo_room > 0) {
1108                 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1109                         rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1110                 }
1111                 if ( count & 1 ) {
1112                         rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);
1113                 }
1114         }
1115 }