10b978496a280d4a02240dc77daca388815b20c8
[dragonfly.git] / sys / dev / serial / rp / rp.c
1 /*
2  * (MPSAFE)
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  * $FreeBSD: src/sys/dev/rp/rp.c,v 1.45.2.2 2002/11/07 22:26:59 tegge Exp $
35  */
36
37 /* 
38  * rp.c - for RocketPort FreeBSD
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/fcntl.h>
44 #include <sys/malloc.h>
45 #include <sys/tty.h>
46 #include <sys/proc.h>
47 #include <sys/priv.h>
48 #include <sys/dkstat.h>
49 #include <sys/conf.h>
50 #include <sys/kernel.h>
51 #include <sys/bus.h>
52 #include <sys/rman.h>
53 #include <sys/thread2.h>
54
55 #include "rpreg.h"
56 #include "rpvar.h"
57
58 static const char RocketPortVersion[] = "3.02";
59
60 static Byte_t RData[RDATASIZE] =
61 {
62    0x00, 0x09, 0xf6, 0x82,
63    0x02, 0x09, 0x86, 0xfb,
64    0x04, 0x09, 0x00, 0x0a,
65    0x06, 0x09, 0x01, 0x0a,
66    0x08, 0x09, 0x8a, 0x13,
67    0x0a, 0x09, 0xc5, 0x11,
68    0x0c, 0x09, 0x86, 0x85,
69    0x0e, 0x09, 0x20, 0x0a,
70    0x10, 0x09, 0x21, 0x0a,
71    0x12, 0x09, 0x41, 0xff,
72    0x14, 0x09, 0x82, 0x00,
73    0x16, 0x09, 0x82, 0x7b,
74    0x18, 0x09, 0x8a, 0x7d,
75    0x1a, 0x09, 0x88, 0x81,
76    0x1c, 0x09, 0x86, 0x7a,
77    0x1e, 0x09, 0x84, 0x81,
78    0x20, 0x09, 0x82, 0x7c,
79    0x22, 0x09, 0x0a, 0x0a
80 };
81
82 static Byte_t RRegData[RREGDATASIZE]=
83 {
84    0x00, 0x09, 0xf6, 0x82,             /* 00: Stop Rx processor */
85    0x08, 0x09, 0x8a, 0x13,             /* 04: Tx software flow control */
86    0x0a, 0x09, 0xc5, 0x11,             /* 08: XON char */
87    0x0c, 0x09, 0x86, 0x85,             /* 0c: XANY */
88    0x12, 0x09, 0x41, 0xff,             /* 10: Rx mask char */
89    0x14, 0x09, 0x82, 0x00,             /* 14: Compare/Ignore #0 */
90    0x16, 0x09, 0x82, 0x7b,             /* 18: Compare #1 */
91    0x18, 0x09, 0x8a, 0x7d,             /* 1c: Compare #2 */
92    0x1a, 0x09, 0x88, 0x81,             /* 20: Interrupt #1 */
93    0x1c, 0x09, 0x86, 0x7a,             /* 24: Ignore/Replace #1 */
94    0x1e, 0x09, 0x84, 0x81,             /* 28: Interrupt #2 */
95    0x20, 0x09, 0x82, 0x7c,             /* 2c: Ignore/Replace #2 */
96    0x22, 0x09, 0x0a, 0x0a              /* 30: Rx FIFO Enable */
97 };
98
99 Byte_t rp_sBitMapClrTbl[8] =
100 {
101    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
102 };
103
104 Byte_t rp_sBitMapSetTbl[8] =
105 {
106    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
107 };
108
109 /***************************************************************************
110 Function: sReadAiopID
111 Purpose:  Read the AIOP idenfication number directly from an AIOP.
112 Call:     sReadAiopID(CtlP, aiop)
113           CONTROLLER_T *CtlP; Ptr to controller structure
114           int aiop: AIOP index
115 Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
116                  is replace by an identifying number.
117           Flag AIOPID_NULL if no valid AIOP is found
118 Warnings: No context switches are allowed while executing this function.
119
120 */
121 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
122 {
123    Byte_t AiopID;               /* ID byte from AIOP */
124
125    crit_enter();
126    rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL);     /* reset AIOP */
127    rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
128    AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
129    crit_exit();
130    if(AiopID == 0x06)
131       return(1);
132    else                                /* AIOP does not exist */
133       return(-1);
134 }
135
136 /***************************************************************************
137 Function: sReadAiopNumChan
138 Purpose:  Read the number of channels available in an AIOP directly from
139           an AIOP.
140 Call:     sReadAiopNumChan(CtlP, aiop)
141           CONTROLLER_T *CtlP; Ptr to controller structure
142           int aiop: AIOP index
143 Return:   int: The number of channels available
144 Comments: The number of channels is determined by write/reads from identical
145           offsets within the SRAM address spaces for channels 0 and 4.
146           If the channel 4 space is mirrored to channel 0 it is a 4 channel
147           AIOP, otherwise it is an 8 channel.
148 Warnings: No context switches are allowed while executing this function.
149 */
150 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
151 {
152    Word_t x, y;
153
154    crit_enter();
155    rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
156    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0);        /* read from SRAM, chan 0 */
157    x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
158    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
159    y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
160    crit_exit();
161    if(x != y)  /* if different must be 8 chan */
162       return(8);
163    else
164       return(4);
165 }
166
167 /***************************************************************************
168 Function: sInitChan
169 Purpose:  Initialization of a channel and channel structure
170 Call:     sInitChan(CtlP,ChP,AiopNum,ChanNum)
171           CONTROLLER_T *CtlP; Ptr to controller structure
172           CHANNEL_T *ChP; Ptr to channel structure
173           int AiopNum; AIOP number within controller
174           int ChanNum; Channel number within AIOP
175 Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
176                number exceeds number of channels available in AIOP.
177 Comments: This function must be called before a channel can be used.
178 Warnings: No range checking on any of the parameters is done.
179
180           No context switches are allowed while executing this function.
181 */
182 int sInitChan(  CONTROLLER_T *CtlP,
183                 CHANNEL_T *ChP,
184                 int AiopNum,
185                 int ChanNum)
186 {
187    int i, ChOff;
188    Byte_t *ChR;
189    static Byte_t R[4];
190
191    if(ChanNum >= CtlP->AiopNumChan[AiopNum])
192       return(FALSE);                   /* exceeds num chans in AIOP */
193
194    crit_enter();
195    /* Channel, AIOP, and controller identifiers */
196    ChP->CtlP = CtlP;
197    ChP->ChanID = CtlP->AiopID[AiopNum];
198    ChP->AiopNum = AiopNum;
199    ChP->ChanNum = ChanNum;
200
201    /* Initialize the channel from the RData array */
202    for(i=0; i < RDATASIZE; i+=4)
203    {
204       R[0] = RData[i];
205       R[1] = RData[i+1] + 0x10 * ChanNum;
206       R[2] = RData[i+2];
207       R[3] = RData[i+3];
208       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)&R[0]));
209    }
210
211    ChR = ChP->R;
212    for(i=0; i < RREGDATASIZE; i+=4)
213    {
214       ChR[i] = RRegData[i];
215       ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
216       ChR[i+2] = RRegData[i+2];
217       ChR[i+3] = RRegData[i+3];
218    }
219
220    /* Indexed registers */
221    ChOff = (Word_t)ChanNum * 0x1000;
222
223    ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
224    ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
225    ChP->BaudDiv[2] = (Byte_t)BRD9600;
226    ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
227    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->BaudDiv[0]);
228
229    ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
230    ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
231    ChP->TxControl[2] = 0;
232    ChP->TxControl[3] = 0;
233    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
234
235    ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
236    ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
237    ChP->RxControl[2] = 0;
238    ChP->RxControl[3] = 0;
239    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
240
241    ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
242    ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
243    ChP->TxEnables[2] = 0;
244    ChP->TxEnables[3] = 0;
245    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxEnables[0]);
246
247    ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
248    ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
249    ChP->TxCompare[2] = 0;
250    ChP->TxCompare[3] = 0;
251    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxCompare[0]);
252
253    ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
254    ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
255    ChP->TxReplace1[2] = 0;
256    ChP->TxReplace1[3] = 0;
257    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace1[0]);
258
259    ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
260    ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
261    ChP->TxReplace2[2] = 0;
262    ChP->TxReplace2[3] = 0;
263    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace2[0]);
264
265    ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
266    ChP->TxFIFO = ChOff + _TX_FIFO;
267
268    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
269    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
270    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
271    rp_writech2(ChP,_INDX_DATA,0);
272    ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
273    ChP->RxFIFO = ChOff + _RX_FIFO;
274
275    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
276    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
277    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
278    rp_writech2(ChP,_INDX_DATA,0);
279    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
280    rp_writech2(ChP,_INDX_DATA,0);
281    ChP->TxPrioCnt = ChOff + _TXP_CNT;
282    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
283    rp_writech1(ChP,_INDX_DATA,0);
284    ChP->TxPrioPtr = ChOff + _TXP_PNTR;
285    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
286    rp_writech1(ChP,_INDX_DATA,0);
287    ChP->TxPrioBuf = ChOff + _TXP_BUF;
288    sEnRxProcessor(ChP);                /* start the Rx processor */
289
290    crit_exit();
291    return(TRUE);
292 }
293
294 /***************************************************************************
295 Function: sStopRxProcessor
296 Purpose:  Stop the receive processor from processing a channel.
297 Call:     sStopRxProcessor(ChP)
298           CHANNEL_T *ChP; Ptr to channel structure
299
300 Comments: The receive processor can be started again with sStartRxProcessor().
301           This function causes the receive processor to skip over the
302           stopped channel.  It does not stop it from processing other channels.
303
304 Warnings: No context switches are allowed while executing this function.
305
306           Do not leave the receive processor stopped for more than one
307           character time.
308
309           After calling this function a delay of 4 uS is required to ensure
310           that the receive processor is no longer processing this channel.
311 */
312 void sStopRxProcessor(CHANNEL_T *ChP)
313 {
314    Byte_t R[4];
315
316    crit_enter();
317    R[0] = ChP->R[0];
318    R[1] = ChP->R[1];
319    R[2] = 0x0a;
320    R[3] = ChP->R[3];
321    rp_writech4(ChP, _INDX_ADDR,*(DWord_t *)&R[0]);
322    crit_exit();
323 }
324
325 /***************************************************************************
326 Function: sFlushRxFIFO
327 Purpose:  Flush the Rx FIFO
328 Call:     sFlushRxFIFO(ChP)
329           CHANNEL_T *ChP; Ptr to channel structure
330 Return:   void
331 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
332           while it is being flushed the receive processor is stopped
333           and the transmitter is disabled.  After these operations a
334           4 uS delay is done before clearing the pointers to allow
335           the receive processor to stop.  These items are handled inside
336           this function.
337 Warnings: No context switches are allowed while executing this function.
338 */
339 void sFlushRxFIFO(CHANNEL_T *ChP)
340 {
341    int i;
342    Byte_t Ch;                   /* channel number within AIOP */
343    int RxFIFOEnabled;                  /* TRUE if Rx FIFO enabled */
344
345    if(sGetRxCnt(ChP) == 0)             /* Rx FIFO empty */
346       return;                          /* don't need to flush */
347
348    crit_enter();
349    RxFIFOEnabled = FALSE;
350    if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
351    {
352       RxFIFOEnabled = TRUE;
353       sDisRxFIFO(ChP);                 /* disable it */
354       for(i=0; i < 2000/200; i++)       /* delay 2 uS to allow proc to disable FIFO*/
355          rp_readch1(ChP,_INT_CHAN);             /* depends on bus i/o timing */
356    }
357    sGetChanStatus(ChP);          /* clear any pending Rx errors in chan stat */
358    Ch = (Byte_t)sGetChanNum(ChP);
359    rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
360    rp_writech1(ChP,_CMD_REG,Ch);                       /* remove reset Rx FIFO count */
361    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
362    rp_writech2(ChP,_INDX_DATA,0);
363    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
364    rp_writech2(ChP,_INDX_DATA,0);
365    if(RxFIFOEnabled)
366       sEnRxFIFO(ChP);                  /* enable Rx FIFO */
367    crit_exit();
368 }
369
370 /***************************************************************************
371 Function: sFlushTxFIFO
372 Purpose:  Flush the Tx FIFO
373 Call:     sFlushTxFIFO(ChP)
374           CHANNEL_T *ChP; Ptr to channel structure
375 Return:   void
376 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
377           while it is being flushed the receive processor is stopped
378           and the transmitter is disabled.  After these operations a
379           4 uS delay is done before clearing the pointers to allow
380           the receive processor to stop.  These items are handled inside
381           this function.
382 Warnings: No context switches are allowed while executing this function.
383 */
384 void sFlushTxFIFO(CHANNEL_T *ChP)
385 {
386    int i;
387    Byte_t Ch;                   /* channel number within AIOP */
388    int TxEnabled;                      /* TRUE if transmitter enabled */
389
390    crit_enter();
391    if(sGetTxCnt(ChP) == 0) {           /* Tx FIFO empty */
392       crit_exit();
393       return;                          /* don't need to flush */
394    }
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    crit_exit();
414 }
415
416 /***************************************************************************
417 Function: sWriteTxPrioByte
418 Purpose:  Write a byte of priority transmit data to a channel
419 Call:     sWriteTxPrioByte(ChP,Data)
420           CHANNEL_T *ChP; Ptr to channel structure
421           Byte_t Data; The transmit data byte
422
423 Return:   int: 1 if the bytes is successfully written, otherwise 0.
424
425 Comments: The priority byte is transmitted before any data in the Tx FIFO.
426
427 Warnings: No context switches are allowed while executing this function.
428 */
429 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
430 {
431    Byte_t DWBuf[4];             /* buffer for double word writes */
432    Word_t *WordPtr;          /* must be far because Win SS != DS */
433
434    crit_enter();
435    if(sGetTxCnt(ChP) > 1)              /* write it to Tx priority buffer */
436    {
437       rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
438       if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) {/* priority buffer busy */
439          crit_exit();
440          return(0);                    /* nothing sent */
441       }
442
443       WordPtr = (Word_t *)(&DWBuf[0]);
444       *WordPtr = ChP->TxPrioBuf;       /* data byte address */
445
446       DWBuf[2] = Data;                 /* data byte value */
447       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
448
449       *WordPtr = ChP->TxPrioCnt;       /* Tx priority count address */
450
451       DWBuf[2] = PRI_PEND + 1;         /* indicate 1 byte pending */
452       DWBuf[3] = 0;                    /* priority buffer pointer */
453       rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
454    }
455    else                                /* write it to Tx FIFO */
456    {
457       sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
458    }
459    crit_exit();
460    return(1);                          /* 1 byte sent */
461 }
462
463 /***************************************************************************
464 Function: sEnInterrupts
465 Purpose:  Enable one or more interrupts for a channel
466 Call:     sEnInterrupts(ChP,Flags)
467           CHANNEL_T *ChP; Ptr to channel structure
468           Word_t Flags: Interrupt enable flags, can be any combination
469              of the following flags:
470                 TXINT_EN:   Interrupt on Tx FIFO empty
471                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
472                             sSetRxTrigger())
473                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
474                 MCINT_EN:   Interrupt on modem input change
475                 CHANINT_EN: Allow channel interrupt signal to the AIOP's
476                             Interrupt Channel Register.
477 Return:   void
478 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
479           enabled.  If an interrupt enable flag is not set in Flags, that
480           interrupt will not be changed.  Interrupts can be disabled with
481           function sDisInterrupts().
482
483           This function sets the appropriate bit for the channel in the AIOP's
484           Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
485           this channel's bit to be set in the AIOP's Interrupt Channel Register.
486
487           Interrupts must also be globally enabled before channel interrupts
488           will be passed on to the host.  This is done with function
489           sEnGlobalInt().
490
491           In some cases it may be desirable to disable interrupts globally but
492           enable channel interrupts.  This would allow the global interrupt
493           status register to be used to determine which AIOPs need service.
494 */
495 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
496 {
497    Byte_t Mask;                 /* Interrupt Mask Register */
498
499    ChP->RxControl[2] |=
500       ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
501
502    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
503
504    ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
505
506    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
507
508    if(Flags & CHANINT_EN)
509    {
510       Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
511       rp_writech1(ChP,_INT_MASK,Mask);
512    }
513 }
514
515 /***************************************************************************
516 Function: sDisInterrupts
517 Purpose:  Disable one or more interrupts for a channel
518 Call:     sDisInterrupts(ChP,Flags)
519           CHANNEL_T *ChP; Ptr to channel structure
520           Word_t Flags: Interrupt flags, can be any combination
521              of the following flags:
522                 TXINT_EN:   Interrupt on Tx FIFO empty
523                 RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
524                             sSetRxTrigger())
525                 SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
526                 MCINT_EN:   Interrupt on modem input change
527                 CHANINT_EN: Disable channel interrupt signal to the
528                             AIOP's Interrupt Channel Register.
529 Return:   void
530 Comments: If an interrupt flag is set in Flags, that interrupt will be
531           disabled.  If an interrupt flag is not set in Flags, that
532           interrupt will not be changed.  Interrupts can be enabled with
533           function sEnInterrupts().
534
535           This function clears the appropriate bit for the channel in the AIOP's
536           Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
537           this channel's bit from being set in the AIOP's Interrupt Channel
538           Register.
539 */
540 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
541 {
542    Byte_t Mask;                 /* Interrupt Mask Register */
543
544    ChP->RxControl[2] &=
545          ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
546    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
547    ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
548    rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
549
550    if(Flags & CHANINT_EN)
551    {
552       Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
553       rp_writech1(ChP,_INT_MASK,Mask);
554    }
555 }
556
557 /*********************************************************************
558   Begin FreeBsd-specific driver code
559 **********************************************************************/
560
561 static timeout_t rpdtrwakeup;
562
563 static  d_open_t        rpopen;
564 static  d_close_t       rpclose;
565 static  d_write_t       rpwrite;
566 static  d_ioctl_t       rpioctl;
567
568 static struct dev_ops rp_ops = {
569         { "rp", 0, D_TTY },
570         .d_open =       rpopen,
571         .d_close =      rpclose,
572         .d_read =       ttyread,
573         .d_write =      rpwrite,
574         .d_ioctl =      rpioctl,
575         .d_kqfilter =   ttykqfilter,
576         .d_revoke =     ttyrevoke
577 };
578
579 static int      rp_num_ports_open = 0;
580 static int      rp_ndevs = 0;
581 static int      minor_to_unit[128];
582 static int      rp_initialized;
583 static struct callout rp_poll_ch;
584
585 static int rp_num_ports[4];     /* Number of ports on each controller */
586
587 #define POLL_INTERVAL 1
588
589 #define CALLOUT_MASK            0x80
590 #define CONTROL_MASK            0x60
591 #define CONTROL_INIT_STATE      0x20
592 #define CONTROL_LOCK_STATE      0x40
593 #define DEV_UNIT(dev)   (MINOR_TO_UNIT(minor(dev))
594 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
595 #define MINOR_MAGIC(dev)        ((minor(dev)) & ~MINOR_MAGIC_MASK)
596 #define IS_CALLOUT(dev)         (minor(dev) & CALLOUT_MASK)
597 #define IS_CONTROL(dev)         (minor(dev) & CONTROL_MASK)
598
599 #define RP_ISMULTIPORT(dev)     ((dev)->id_flags & 0x1)
600 #define RP_MPMASTER(dev)        (((dev)->id_flags >> 8) & 0xff)
601 #define RP_NOTAST4(dev)         ((dev)->id_flags & 0x04)
602
603 static  struct  rp_port *p_rp_addr[4];
604 static  struct  rp_port *p_rp_table[MAX_RP_PORTS];
605 #define rp_addr(unit)   (p_rp_addr[unit])
606 #define rp_table(port)  (p_rp_table[port])
607
608 /*
609  * The top-level routines begin here
610  */
611
612 static  int     rpparam (struct tty *, struct termios *);
613 static  void    rpstart (struct tty *);
614 static  void    rpstop (struct tty *, int);
615 static  void    rphardclose     (struct rp_port *);
616 static  void    rp_disc_optim   (struct tty *tp, struct termios *t);
617
618 /*
619  * NOTE: Must be called with tty_token held
620  */
621 static void
622 rp_do_receive(struct rp_port *rp, struct tty *tp,
623                         CHANNEL_t *cp, unsigned int ChanStatus)
624 {
625         unsigned        int     CharNStat;
626         int     ToRecv, wRecv, ch, ttynocopy;
627
628         ASSERT_LWKT_TOKEN_HELD(&tty_token);
629         ToRecv = sGetRxCnt(cp);
630         if(ToRecv == 0)
631                 return;
632
633 /*      If status indicates there are errored characters in the
634         FIFO, then enter status mode (a word in FIFO holds
635         characters and status)
636 */
637
638         if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
639                 if(!(ChanStatus & STATMODE)) {
640                         ChanStatus |= STATMODE;
641                         sEnRxStatusMode(cp);
642                 }
643         }
644 /*
645         if we previously entered status mode then read down the
646         FIFO one word at a time, pulling apart the character and
647         the status. Update error counters depending on status.
648 */
649         if(ChanStatus & STATMODE) {
650                 while(ToRecv) {
651                         if(tp->t_state & TS_TBLOCK) {
652                                 break;
653                         }
654                         CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
655                         ch = CharNStat & 0xff;
656
657                         if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
658                                 ch |= TTY_FE;
659                         else if (CharNStat & STMPARITYH)
660                                 ch |= TTY_PE;
661                         else if (CharNStat & STMRCVROVRH)
662                                 rp->rp_overflows++;
663
664                         (*linesw[tp->t_line].l_rint)(ch, tp);
665                         ToRecv--;
666                 }
667 /*
668         After emtying FIFO in status mode, turn off status mode
669 */
670
671                 if(sGetRxCnt(cp) == 0) {
672                         sDisRxStatusMode(cp);
673                 }
674         } else {
675                 /*
676                  * Avoid the grotesquely inefficient lineswitch routine
677                  * (ttyinput) in "raw" mode.  It usually takes about 450
678                  * instructions (that's without canonical processing or echo!).
679                  * slinput is reasonably fast (usually 40 instructions plus
680                  * call overhead).
681                  */
682                 ToRecv = sGetRxCnt(cp);
683                 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
684                         if ( ToRecv > RXFIFO_SIZE ) {
685                                 ToRecv = RXFIFO_SIZE;
686                         }
687                         wRecv = ToRecv >> 1;
688                         if ( wRecv ) {
689                                 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
690                         }
691                         if ( ToRecv & 1 ) {
692                                 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
693                         }
694                         tk_nin += ToRecv;
695                         tk_rawcc += ToRecv;
696                         tp->t_rawcc += ToRecv;
697                         ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
698                         ttwakeup(tp);
699                 } else {
700                         while (ToRecv) {
701                                 if(tp->t_state & TS_TBLOCK) {
702                                         break;
703                                 }
704                                 ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
705                                 crit_enter();
706                                 (*linesw[tp->t_line].l_rint)(ch, tp);
707                                 crit_exit();
708                                 ToRecv--;
709                         }
710                 }
711         }
712 }
713
714 /*
715  * NOTE: Must be called with tty_token held
716  */
717 static void
718 rp_handle_port(struct rp_port *rp)
719 {
720         CHANNEL_t       *cp;
721         struct  tty     *tp;
722         unsigned        int     IntMask, ChanStatus;
723
724         ASSERT_LWKT_TOKEN_HELD(&tty_token);
725
726         if(!rp)
727                 return;
728
729         cp = &rp->rp_channel;
730         tp = rp->rp_tty;
731         IntMask = sGetChanIntID(cp);
732         IntMask = IntMask & rp->rp_intmask;
733         ChanStatus = sGetChanStatus(cp);
734         if(IntMask & RXF_TRIG)
735                 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
736                         rp_do_receive(rp, tp, cp, ChanStatus);
737                 }
738         if(IntMask & DELTA_CD) {
739                 if(ChanStatus & CD_ACT) {
740                         if(!(tp->t_state & TS_CARR_ON) ) {
741                                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
742                         }
743                 } else {
744                         if((tp->t_state & TS_CARR_ON)) {
745                                 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
746                                 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
747                                         rphardclose(rp);
748                                 }
749                         }
750                 }
751         }
752 /*      oldcts = rp->rp_cts;
753         rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
754         if(oldcts != rp->rp_cts) {
755                 kprintf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
756         }
757 */
758 }
759
760 static void rp_do_poll(void *not_used)
761 {
762         CONTROLLER_t    *ctl;
763         struct rp_port  *rp;
764         struct tty      *tp;
765         int     unit, aiop, ch, line, count;
766         unsigned char   CtlMask, AiopMask;
767
768         lwkt_gettoken(&tty_token);
769         for(unit = 0; unit < rp_ndevs; unit++) {
770         rp = rp_addr(unit);
771         ctl = rp->rp_ctlp;
772         CtlMask = ctl->ctlmask(ctl);
773         for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
774                 if(CtlMask & 1) {
775                         AiopMask = sGetAiopIntStatus(ctl, aiop);
776                         for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
777                                 if(AiopMask & 1) {
778                                         line = (unit << 5) | (aiop << 3) | ch;
779                                         rp = rp_table(line);
780                                         rp_handle_port(rp);
781                                 }
782                         }
783                 }
784         }
785
786         for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
787                         line++, rp++) {
788                 tp = rp->rp_tty;
789                 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
790                         count = sGetTxCnt(&rp->rp_channel);
791                         if(count == 0)
792                                 tp->t_state &= ~(TS_BUSY);
793                         if(!(tp->t_state & TS_TTSTOP) &&
794                                 (count <= rp->rp_restart)) {
795                                 (*linesw[tp->t_line].l_start)(tp);
796                         }
797                 }
798         }
799         }
800         if(rp_num_ports_open)
801                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
802         lwkt_reltoken(&tty_token);
803 }
804
805 int
806 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
807 {
808         int     unit;
809         int     num_chan;
810         int     aiop, chan, port;
811         int     ChanStatus, line, i, count;
812         int     retval;
813         struct  rp_port *rp;
814         struct  tty     *tty;
815
816         lwkt_gettoken(&tty_token);
817         unit = device_get_unit(ctlp->dev);
818
819         kprintf("RocketPort%d (Version %s) %d ports.\n", unit,
820                 RocketPortVersion, num_ports);
821         rp_num_ports[unit] = num_ports;
822
823         ctlp->rp = rp = kmalloc(sizeof(struct rp_port) * num_ports, 
824                                 M_TTYS, M_WAITOK | M_ZERO);
825
826         count = unit * 32;      /* board times max ports per card SG */
827         for(i=count;i < (count + rp_num_ports[unit]);i++)
828                 minor_to_unit[i] = unit;
829
830         ctlp->tty = tty = kmalloc(sizeof(struct tty) * num_ports,
831                                     M_TTYS, M_WAITOK | M_ZERO);
832
833         crit_enter();
834         rp_addr(unit) = rp;
835         crit_exit();
836
837         for (i = 0 ; i < rp_num_ports[unit] ; i++) {
838                 make_dev(&rp_ops, ((unit + 1) << 16) | i,
839                           UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
840                           i <= 9 ? '0' + i : 'a' + i - 10);
841                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x20,
842                           UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
843                           i <= 9 ? '0' + i : 'a' + i - 10);
844                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x40,
845                           UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
846                           i <= 9 ? '0' + i : 'a' + i - 10);
847                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0x80,
848                           UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
849                           i <= 9 ? '0' + i : 'a' + i - 10);
850                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xa0,
851                           UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
852                           i <= 9 ? '0' + i : 'a' + i - 10);
853                 make_dev(&rp_ops, ((unit + 1) << 16) | i | 0xc0,
854                           UID_ROOT, GID_WHEEL, 0666, "cualR%c",
855                           i <= 9 ? '0' + i : 'a' + i - 10);
856         }
857
858         port = 0;
859         for(aiop=0; aiop < num_aiops; aiop++) {
860                 num_chan = sGetAiopNumChan(ctlp, aiop);
861                 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
862                         rp->rp_tty = tty;
863                         rp->rp_port = port;
864                         rp->rp_ctlp = ctlp;
865                         rp->rp_unit = unit;
866                         rp->rp_chan = chan;
867                         rp->rp_aiop = aiop;
868
869                         tty->t_line = 0;
870         /*              tty->t_termios = deftermios;
871         */
872                         rp->dtr_wait = 3 * hz;
873                         rp->it_in.c_iflag = 0;
874                         rp->it_in.c_oflag = 0;
875                         rp->it_in.c_cflag = TTYDEF_CFLAG;
876                         rp->it_in.c_lflag = 0;
877                         termioschars(&rp->it_in);
878         /*              termioschars(&tty->t_termios);
879         */
880                         rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
881                         rp->it_out = rp->it_in;
882
883                         rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
884                                 DELTA_CD | DELTA_CTS | DELTA_DSR;
885                         if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
886                                 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
887                                               unit, aiop, chan);
888                                 retval = ENXIO;
889                                 goto nogo;
890                         }
891                         ChanStatus = sGetChanStatus(&rp->rp_channel);
892                         rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
893                         line = (unit << 5) | (aiop << 3) | chan;
894                         rp_table(line) = rp;
895                 }
896         }
897
898         rp_ndevs++;
899         lwkt_reltoken(&tty_token);
900         return (0);
901
902 nogo:
903         rp_releaseresource(ctlp);
904         lwkt_reltoken(&tty_token);
905         return (retval);
906 }
907
908 void
909 rp_releaseresource(CONTROLLER_t *ctlp)
910 {
911         int i, unit;
912
913         lwkt_gettoken(&tty_token);
914         unit = device_get_unit(ctlp->dev);
915
916         if (ctlp->rp != NULL) {
917                 crit_enter();
918                 for (i = 0 ; i < NELEM(p_rp_addr) ; i++)
919                         if (p_rp_addr[i] == ctlp->rp)
920                                 p_rp_addr[i] = NULL;
921                 for (i = 0 ; i < NELEM(p_rp_table) ; i++)
922                         if (p_rp_table[i] == ctlp->rp)
923                                 p_rp_table[i] = NULL;
924                 crit_exit();
925                 kfree(ctlp->rp, M_DEVBUF);
926                 ctlp->rp = NULL;
927         }
928         if (ctlp->tty != NULL) {
929                 kfree(ctlp->tty, M_DEVBUF);
930                 ctlp->tty = NULL;
931         }
932         if (ctlp->dev != NULL)
933                 ctlp->dev = NULL;
934         dev_ops_remove_minor(&rp_ops, /*0xffff0000, */(unit + 1) << 16);
935         lwkt_reltoken(&tty_token);
936 }
937
938 int
939 rpopen(struct dev_open_args *ap)
940 {
941         cdev_t dev = ap->a_head.a_dev;
942         struct  rp_port *rp;
943         int     unit, port, mynor, umynor, flags;  /* SG */
944         struct  tty     *tp;
945         int     error;
946         unsigned int    IntMask, ChanStatus;
947
948         lwkt_gettoken(&tty_token);
949         if (!rp_initialized) {
950                 rp_initialized = 1;
951                 callout_init_mp(&rp_poll_ch);
952         }
953
954    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
955         port  = (minor(dev) & 0x1f);                /* SG */
956         mynor = (port + umynor);                    /* SG */
957         unit = minor_to_unit[mynor];
958         if (rp_addr(unit) == NULL) {
959                 lwkt_reltoken(&tty_token);
960                 return (ENXIO);
961         }
962         if(IS_CONTROL(dev)) {
963                 lwkt_reltoken(&tty_token);
964                 return(0);
965         }
966         rp = rp_addr(unit) + port;
967 /*      rp->rp_tty = &rp_tty[rp->rp_port];
968 */
969         callout_init_mp(&rp->wakeup_callout);
970         tp = rp->rp_tty;
971         dev->si_tty = tp;
972
973         crit_enter();
974
975 open_top:
976         while(rp->state & ~SET_DTR) {
977                 error = tsleep(&rp->dtr_wait, PCATCH, "rpdtr", 0);
978                 if(error != 0)
979                         goto out;
980         }
981
982         if(tp->t_state & TS_ISOPEN) {
983                 if(IS_CALLOUT(dev)) {
984                         if(!rp->active_out) {
985                                 error = EBUSY;
986                                 goto out;
987                         }
988                 } else {
989                         if(rp->active_out) {
990                                 if(ap->a_oflags & O_NONBLOCK) {
991                                         error = EBUSY;
992                                         goto out;
993                                 }
994                                 error = tsleep(&rp->active_out,
995                                             PCATCH, "rpbi", 0);
996                                 if(error != 0)
997                                         goto out;
998                                 goto open_top;
999                         }
1000                 }
1001                 if(tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0) != 0) {
1002                         crit_exit();
1003                         error = EBUSY;
1004                         goto out2;
1005                 }
1006         }
1007         else {
1008                 tp->t_dev = dev;
1009                 tp->t_param = rpparam;
1010                 tp->t_oproc = rpstart;
1011                 tp->t_stop = rpstop;
1012                 tp->t_line = 0;
1013                 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1014                 tp->t_ififosize = 512;
1015                 tp->t_ispeedwat = (speed_t)-1;
1016                 tp->t_ospeedwat = (speed_t)-1;
1017                 flags = 0;
1018                 flags |= SET_RTS;
1019                 flags |= SET_DTR;
1020                 rp->rp_channel.TxControl[3] =
1021                         ((rp->rp_channel.TxControl[3]
1022                         & ~(SET_RTS | SET_DTR)) | flags);
1023                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1024                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1025                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1026                 sDisRxStatusMode(&rp->rp_channel);
1027                 sFlushRxFIFO(&rp->rp_channel);
1028                 sFlushTxFIFO(&rp->rp_channel);
1029
1030                 sEnInterrupts(&rp->rp_channel,
1031                         (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1032                 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1033
1034                 sDisRxStatusMode(&rp->rp_channel);
1035                 sClrTxXOFF(&rp->rp_channel);
1036
1037 /*              sDisRTSFlowCtl(&rp->rp_channel);
1038                 sDisCTSFlowCtl(&rp->rp_channel);
1039 */
1040                 sDisTxSoftFlowCtl(&rp->rp_channel);
1041
1042                 sStartRxProcessor(&rp->rp_channel);
1043
1044                 sEnRxFIFO(&rp->rp_channel);
1045                 sEnTransmit(&rp->rp_channel);
1046
1047 /*              sSetDTR(&rp->rp_channel);
1048                 sSetRTS(&rp->rp_channel);
1049 */
1050
1051                 ++rp->wopeners;
1052                 error = rpparam(tp, &tp->t_termios);
1053                 --rp->wopeners;
1054                 if(error != 0) {
1055                         crit_exit();
1056                         lwkt_reltoken(&tty_token);
1057                         return(error);
1058                 }
1059
1060                 rp_num_ports_open++;
1061
1062                 IntMask = sGetChanIntID(&rp->rp_channel);
1063                 IntMask = IntMask & rp->rp_intmask;
1064                 ChanStatus = sGetChanStatus(&rp->rp_channel);
1065                 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1066                         if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1067                                         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1068                         }
1069                 }
1070
1071         if(rp_num_ports_open == 1)
1072                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1073
1074         }
1075
1076         if(!(ap->a_oflags&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1077                 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1078                 ++rp->wopeners;
1079                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "rpdcd", 0);
1080                 --rp->wopeners;
1081                 if(error != 0)
1082                         goto out;
1083                 goto open_top;
1084         }
1085         error = (*linesw[tp->t_line].l_open)(dev, tp);
1086
1087         rp_disc_optim(tp, &tp->t_termios);
1088         if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1089                 rp->active_out = TRUE;
1090
1091 /*      if(rp_num_ports_open == 1)
1092                 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1093 */
1094 out:
1095         crit_exit();
1096         if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1097                 rphardclose(rp);
1098         }
1099 out2:
1100         if (error == 0)
1101                 device_busy(rp->rp_ctlp->dev);
1102         lwkt_reltoken(&tty_token);
1103         return(error);
1104 }
1105
1106 int
1107 rpclose(struct dev_close_args *ap)
1108 {
1109         cdev_t dev = ap->a_head.a_dev;
1110         int     unit, mynor, umynor, port; /* SG */
1111         struct  rp_port *rp;
1112         struct  tty     *tp;
1113
1114         lwkt_gettoken(&tty_token);
1115    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1116         port  = (minor(dev) & 0x1f);                /* SG */
1117         mynor = (port + umynor);                    /* SG */
1118    unit = minor_to_unit[mynor];                /* SG */
1119
1120         if(IS_CONTROL(dev)) {
1121                 lwkt_reltoken(&tty_token);
1122                 return(0);
1123         }
1124         rp = rp_addr(unit) + port;
1125         tp = rp->rp_tty;
1126
1127         crit_enter();
1128         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
1129         rp_disc_optim(tp, &tp->t_termios);
1130         rpstop(tp, FREAD | FWRITE);
1131         rphardclose(rp);
1132
1133         tp->t_state &= ~TS_BUSY;
1134         ttyclose(tp);
1135
1136         crit_exit();
1137
1138         device_unbusy(rp->rp_ctlp->dev);
1139
1140         lwkt_reltoken(&tty_token);
1141         return(0);
1142 }
1143
1144 /*
1145  * NOTE: Must be called with tty_token held
1146  */
1147 static void
1148 rphardclose(struct rp_port *rp)
1149 {
1150         struct  tty     *tp;
1151         CHANNEL_t       *cp;
1152
1153         ASSERT_LWKT_TOKEN_HELD(&tty_token);
1154         cp = &rp->rp_channel;
1155         tp = rp->rp_tty;
1156
1157         sFlushRxFIFO(cp);
1158         sFlushTxFIFO(cp);
1159         sDisTransmit(cp);
1160         sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1161         sDisRTSFlowCtl(cp);
1162         sDisCTSFlowCtl(cp);
1163         sDisTxSoftFlowCtl(cp);
1164         sClrTxXOFF(cp);
1165
1166         if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1167                 sClrDTR(cp);
1168         }
1169         if(IS_CALLOUT(tp->t_dev)) {
1170                 sClrDTR(cp);
1171         }
1172         if(rp->dtr_wait != 0) {
1173                 callout_reset(&rp->wakeup_callout, rp->dtr_wait,
1174                               rpdtrwakeup, rp);
1175                 rp->state |= ~SET_DTR;
1176         }
1177
1178         rp->active_out = FALSE;
1179         wakeup(&rp->active_out);
1180         wakeup(TSA_CARR_ON(tp));
1181 }
1182
1183 static
1184 int
1185 rpwrite(struct dev_write_args *ap)
1186 {
1187         cdev_t dev = ap->a_head.a_dev;
1188         struct  rp_port *rp;
1189         struct  tty     *tp;
1190         int     unit, mynor, port, umynor, error = 0; /* SG */
1191
1192    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1193         port  = (minor(dev) & 0x1f);                /* SG */
1194         mynor = (port + umynor);                    /* SG */
1195    unit = minor_to_unit[mynor];                /* SG */
1196
1197         if(IS_CONTROL(dev))
1198                 return(ENODEV);
1199         lwkt_gettoken(&tty_token);
1200         rp = rp_addr(unit) + port;
1201         tp = rp->rp_tty;
1202         while(rp->rp_disable_writes) {
1203                 rp->rp_waiting = 1;
1204                 error = ttysleep(tp, (caddr_t)rp, PCATCH, "rp_write", 0);
1205                 if (error) {
1206                         lwkt_reltoken(&tty_token);
1207                         return(error);
1208                 }
1209         }
1210
1211         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1212         lwkt_reltoken(&tty_token);
1213         return error;
1214 }
1215
1216 static void
1217 rpdtrwakeup(void *chan)
1218 {
1219         struct  rp_port *rp;
1220
1221         lwkt_gettoken(&tty_token);
1222         rp = (struct rp_port *)chan;
1223         rp->state &= SET_DTR;
1224         wakeup(&rp->dtr_wait);
1225         lwkt_reltoken(&tty_token);
1226 }
1227
1228 int
1229 rpioctl(struct dev_ioctl_args *ap)
1230 {
1231         cdev_t dev = ap->a_head.a_dev;
1232         u_long cmd = ap->a_cmd;
1233         caddr_t data = ap->a_data;
1234         struct rp_port  *rp;
1235         struct tty      *tp;
1236         int     unit, mynor, port, umynor;            /* SG */
1237         int     error = 0;
1238         int     arg, flags, result, ChanStatus;
1239
1240         lwkt_gettoken(&tty_token);
1241    umynor = (((minor(dev) >> 16) -1) * 32);    /* SG */
1242         port  = (minor(dev) & 0x1f);                /* SG */
1243         mynor = (port + umynor);                    /* SG */
1244         unit = minor_to_unit[mynor];
1245         rp = rp_addr(unit) + port;
1246
1247         if(IS_CONTROL(dev)) {
1248                 struct  termios *ct;
1249
1250                 switch (IS_CONTROL(dev)) {
1251                 case CONTROL_INIT_STATE:
1252                         ct =  IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1253                         break;
1254                 case CONTROL_LOCK_STATE:
1255                         ct =  IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1256                         break;
1257                 default:
1258                         lwkt_reltoken(&tty_token);
1259                         return(ENODEV);         /* /dev/nodev */
1260                 }
1261                 switch (cmd) {
1262                 case TIOCSETA:
1263                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1264                         if(error != 0) {
1265                                 lwkt_reltoken(&tty_token);
1266                                 return(error);
1267                         }
1268                         *ct = *(struct termios *)data;
1269                         lwkt_reltoken(&tty_token);
1270                         return(0);
1271                 case TIOCGETA:
1272                         *(struct termios *)data = *ct;
1273                         lwkt_reltoken(&tty_token);
1274                         return(0);
1275                 case TIOCGETD:
1276                         *(int *)data = TTYDISC;
1277                         lwkt_reltoken(&tty_token);
1278                         return(0);
1279                 case TIOCGWINSZ:
1280                         bzero(data, sizeof(struct winsize));
1281                         lwkt_reltoken(&tty_token);
1282                         return(0);
1283                 default:
1284                         lwkt_reltoken(&tty_token);
1285                         return(ENOTTY);
1286                 }
1287         }
1288
1289         tp = rp->rp_tty;
1290
1291         if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1292                 int     cc;
1293                 struct  termios *dt = (struct termios *)data;
1294                 struct  termios *lt = IS_CALLOUT(dev)
1295                                         ? &rp->lt_out : &rp->lt_in;
1296
1297                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1298                                 | (dt->c_iflag & ~lt->c_iflag);
1299                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1300                                 | (dt->c_oflag & ~lt->c_oflag);
1301                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1302                                 | (dt->c_cflag & ~lt->c_cflag);
1303                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1304                                 | (dt->c_lflag & ~lt->c_lflag);
1305                 for(cc = 0; cc < NCCS; ++cc)
1306                         if(lt->c_cc[cc] != 0)
1307                                 dt->c_cc[cc] = tp->t_cc[cc];
1308                 if(lt->c_ispeed != 0)
1309                         dt->c_ispeed = tp->t_ispeed;
1310                 if(lt->c_ospeed != 0)
1311                         dt->c_ospeed = tp->t_ospeed;
1312         }
1313
1314         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data,
1315                                               ap->a_fflag, ap->a_cred);
1316         if(error != ENOIOCTL) {
1317                 lwkt_reltoken(&tty_token);
1318                 return(error);
1319         }
1320         crit_enter();
1321
1322         flags = rp->rp_channel.TxControl[3];
1323
1324         error = ttioctl(tp, cmd, data, ap->a_fflag);
1325         flags = rp->rp_channel.TxControl[3];
1326         rp_disc_optim(tp, &tp->t_termios);
1327         if(error != ENOIOCTL) {
1328                 crit_exit();
1329                 lwkt_reltoken(&tty_token);
1330                 return(error);
1331         }
1332         switch(cmd) {
1333         case TIOCSBRK:
1334                 sSendBreak(&rp->rp_channel);
1335                 break;
1336
1337         case TIOCCBRK:
1338                 sClrBreak(&rp->rp_channel);
1339                 break;
1340
1341         case TIOCSDTR:
1342                 sSetDTR(&rp->rp_channel);
1343                 sSetRTS(&rp->rp_channel);
1344                 break;
1345
1346         case TIOCCDTR:
1347                 sClrDTR(&rp->rp_channel);
1348                 break;
1349
1350         case TIOCMSET:
1351                 arg = *(int *) data;
1352                 flags = 0;
1353                 if(arg & TIOCM_RTS)
1354                         flags |= SET_RTS;
1355                 if(arg & TIOCM_DTR)
1356                         flags |= SET_DTR;
1357                 rp->rp_channel.TxControl[3] =
1358                         ((rp->rp_channel.TxControl[3]
1359                         & ~(SET_RTS | SET_DTR)) | flags);
1360                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1361                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1362                 break;
1363         case TIOCMBIS:
1364                 arg = *(int *) data;
1365                 flags = 0;
1366                 if(arg & TIOCM_RTS)
1367                         flags |= SET_RTS;
1368                 if(arg & TIOCM_DTR)
1369                         flags |= SET_DTR;
1370                 rp->rp_channel.TxControl[3] |= flags;
1371                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1372                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1373                 break;
1374         case TIOCMBIC:
1375                 arg = *(int *) data;
1376                 flags = 0;
1377                 if(arg & TIOCM_RTS)
1378                         flags |= SET_RTS;
1379                 if(arg & TIOCM_DTR)
1380                         flags |= SET_DTR;
1381                 rp->rp_channel.TxControl[3] &= ~flags;
1382                 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1383                         *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1384                 break;
1385
1386
1387         case TIOCMGET:
1388                 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1389                 flags = rp->rp_channel.TxControl[3];
1390                 result = TIOCM_LE; /* always on while open for some reason */
1391                 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1392                         | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1393                         | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1394                         | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1395                         | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1396
1397                 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1398                 {
1399                         result |= TIOCM_RTS;
1400                 }
1401
1402                 *(int *)data = result;
1403                 break;
1404         case TIOCMSDTRWAIT:
1405                 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1406                 if(error != 0) {
1407                         crit_exit();
1408                         lwkt_reltoken(&tty_token);
1409                         return(error);
1410                 }
1411                 rp->dtr_wait = *(int *)data * hz/100;
1412                 break;
1413         case TIOCMGDTRWAIT:
1414                 *(int *)data = rp->dtr_wait * 100/hz;
1415                 break;
1416         default:
1417                 crit_exit();
1418                 lwkt_reltoken(&tty_token);
1419                 return ENOTTY;
1420         }
1421         crit_exit();
1422         lwkt_reltoken(&tty_token);
1423         return(0);
1424 }
1425
1426 static struct speedtab baud_table[] = {
1427         {B0,    0},             {B50,   BRD50},         {B75,   BRD75},
1428         {B110,  BRD110},        {B134,  BRD134},        {B150,  BRD150},
1429         {B200,  BRD200},        {B300,  BRD300},        {B600,  BRD600},
1430         {B1200, BRD1200},       {B1800, BRD1800},       {B2400, BRD2400},
1431         {B4800, BRD4800},       {B9600, BRD9600},       {B19200, BRD19200},
1432         {B38400, BRD38400},     {B7200, BRD7200},       {B14400, BRD14400},
1433                                 {B57600, BRD57600},     {B76800, BRD76800},
1434         {B115200, BRD115200},   {B230400, BRD230400},
1435         {-1,    -1}
1436 };
1437
1438 static int
1439 rpparam(struct tty *tp, struct termios *t)
1440 {
1441         struct rp_port  *rp;
1442         CHANNEL_t       *cp;
1443         int     unit, mynor, port, umynor;               /* SG */
1444         int     cflag, iflag, oflag, lflag;
1445         int     ospeed;
1446 #ifdef RPCLOCAL
1447         int     devshift;
1448 #endif
1449
1450         lwkt_gettoken(&tty_token);
1451    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1452         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1453         mynor = (port + umynor);                          /* SG */
1454
1455         unit = minor_to_unit[mynor];
1456         rp = rp_addr(unit) + port;
1457         cp = &rp->rp_channel;
1458         crit_enter();
1459
1460         cflag = t->c_cflag;
1461 #ifdef RPCLOCAL
1462         devshift = umynor / 32;
1463         devshift = 1 << devshift;
1464         if ( devshift & RPCLOCAL ) {
1465                 cflag |= CLOCAL;
1466         }
1467 #endif
1468         iflag = t->c_iflag;
1469         oflag = t->c_oflag;
1470         lflag = t->c_lflag;
1471
1472         ospeed = ttspeedtab(t->c_ispeed, baud_table);
1473         if(ospeed < 0 || t->c_ispeed != t->c_ospeed) {
1474                 crit_exit();
1475                 lwkt_reltoken(&tty_token);
1476                 return(EINVAL);
1477         }
1478
1479         tp->t_ispeed = t->c_ispeed;
1480         tp->t_ospeed = t->c_ospeed;
1481         tp->t_cflag = cflag;
1482         tp->t_iflag = iflag;
1483         tp->t_oflag = oflag;
1484         tp->t_lflag = lflag;
1485
1486         if(t->c_ospeed == 0) {
1487                 sClrDTR(cp);
1488                 crit_exit();
1489                 lwkt_reltoken(&tty_token);
1490                 return(0);
1491         }
1492         rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1493
1494         /* Set baud rate ----- we only pay attention to ispeed */
1495         sSetDTR(cp);
1496         sSetRTS(cp);
1497         sSetBaud(cp, ospeed);
1498
1499         if(cflag & CSTOPB) {
1500                 sSetStop2(cp);
1501         } else {
1502                 sSetStop1(cp);
1503         }
1504
1505         if(cflag & PARENB) {
1506                 sEnParity(cp);
1507                 if(cflag & PARODD) {
1508                         sSetOddParity(cp);
1509                 } else {
1510                         sSetEvenParity(cp);
1511                 }
1512         }
1513         else {
1514                 sDisParity(cp);
1515         }
1516         if((cflag & CSIZE) == CS8) {
1517                 sSetData8(cp);
1518                 rp->rp_imask = 0xFF;
1519         } else {
1520                 sSetData7(cp);
1521                 rp->rp_imask = 0x7F;
1522         }
1523
1524         if(iflag & ISTRIP) {
1525                 rp->rp_imask &= 0x7F;
1526         }
1527
1528         if(cflag & CLOCAL) {
1529                 rp->rp_intmask &= ~DELTA_CD;
1530         } else {
1531                 rp->rp_intmask |= DELTA_CD;
1532         }
1533
1534         /* Put flow control stuff here */
1535
1536         if(cflag & CCTS_OFLOW) {
1537                 sEnCTSFlowCtl(cp);
1538         } else {
1539                 sDisCTSFlowCtl(cp);
1540         }
1541
1542         if(cflag & CRTS_IFLOW) {
1543                 rp->rp_rts_iflow = 1;
1544         } else {
1545                 rp->rp_rts_iflow = 0;
1546         }
1547
1548         if(cflag & CRTS_IFLOW) {
1549                 sEnRTSFlowCtl(cp);
1550         } else {
1551                 sDisRTSFlowCtl(cp);
1552         }
1553         rp_disc_optim(tp, t);
1554
1555         if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1556                 tp->t_state |= TS_CARR_ON;
1557                 wakeup(TSA_CARR_ON(tp));
1558         }
1559
1560 /*      tp->t_state |= TS_CAN_BYPASS_L_RINT;
1561         flags = rp->rp_channel.TxControl[3];
1562         if(flags & SET_DTR)
1563         else
1564         if(flags & SET_RTS)
1565         else
1566 */
1567         crit_exit();
1568
1569         lwkt_reltoken(&tty_token);
1570         return(0);
1571 }
1572
1573 static void
1574 rp_disc_optim(struct tty *tp, struct termios *t)
1575 {
1576         lwkt_gettoken(&tty_token);
1577         if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1578                 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1579                 &&(!(t->c_iflag & PARMRK)
1580                   ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1581                 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1582                 && linesw[tp->t_line].l_rint == ttyinput)
1583                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1584         else
1585                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1586         lwkt_reltoken(&tty_token);
1587 }
1588
1589 static void
1590 rpstart(struct tty *tp)
1591 {
1592         struct rp_port  *rp;
1593         CHANNEL_t       *cp;
1594         struct  clist   *qp;
1595         int     unit, mynor, port, umynor;               /* SG */
1596         int     xmit_fifo_room;
1597         int     count, wcount;
1598
1599
1600         lwkt_gettoken(&tty_token);
1601    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1602         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1603         mynor = (port + umynor);                          /* SG */
1604         unit = minor_to_unit[mynor];
1605         rp = rp_addr(unit) + port;
1606         cp = &rp->rp_channel;
1607         crit_enter();
1608
1609         if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1610                 ttwwakeup(tp);
1611                 crit_exit();
1612                 lwkt_reltoken(&tty_token);
1613                 return;
1614         }
1615         if(rp->rp_xmit_stopped) {
1616                 sEnTransmit(cp);
1617                 rp->rp_xmit_stopped = 0;
1618         }
1619         count = sGetTxCnt(cp);
1620
1621         if(tp->t_outq.c_cc == 0) {
1622                 if((tp->t_state & TS_BUSY) && (count == 0)) {
1623                         tp->t_state &= ~TS_BUSY;
1624                 }
1625                 ttwwakeup(tp);
1626                 crit_exit();
1627                 lwkt_reltoken(&tty_token);
1628                 return;
1629         }
1630         xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1631         qp = &tp->t_outq;
1632         if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1633                 tp->t_state |= TS_BUSY;
1634                 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1635                 wcount = count >> 1;
1636                 if ( wcount ) {
1637                         rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1638                 }
1639                 if ( count & 1 ) {
1640                         rp_writech1(cp, sGetTxRxDataIO(cp),
1641                                     ((unsigned char *)(rp->TxBuf))[(count-1)]);
1642                 }
1643         }
1644         rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1645
1646         ttwwakeup(tp);
1647         crit_exit();
1648         lwkt_reltoken(&tty_token);
1649 }
1650
1651 static
1652 void
1653 rpstop(struct tty *tp, int flag)
1654 {
1655         struct rp_port  *rp;
1656         CHANNEL_t       *cp;
1657         int     unit, mynor, port, umynor;                  /* SG */
1658
1659         lwkt_gettoken(&tty_token);
1660    umynor = (((minor(tp->t_dev) >> 16) -1) * 32);    /* SG */
1661         port  = (minor(tp->t_dev) & 0x1f);                /* SG */
1662         mynor = (port + umynor);                          /* SG */
1663         unit = minor_to_unit[mynor];
1664         rp = rp_addr(unit) + port;
1665         cp = &rp->rp_channel;
1666
1667         crit_enter();
1668
1669         if(tp->t_state & TS_BUSY) {
1670                 if((tp->t_state&TS_TTSTOP) == 0) {
1671                         sFlushTxFIFO(cp);
1672                 } else {
1673                         if(rp->rp_xmit_stopped == 0) {
1674                                 sDisTransmit(cp);
1675                                 rp->rp_xmit_stopped = 1;
1676                         }
1677                 }
1678         }
1679         crit_exit();
1680         rpstart(tp);
1681         lwkt_reltoken(&tty_token);
1682 }