kernel: Remove the COMPAT_43 kernel option along with all related code.
[dragonfly.git] / sys / dev / serial / rp / rp.c
blob10b978496a280d4a02240dc77daca388815b20c8
1 /*
2 * (MPSAFE)
4 * Copyright (c) Comtrol Corporation <support@comtrol.com>
5 * All rights reserved.
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.
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.
34 * $FreeBSD: src/sys/dev/rp/rp.c,v 1.45.2.2 2002/11/07 22:26:59 tegge Exp $
37 /*
38 * rp.c - for RocketPort FreeBSD
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>
55 #include "rpreg.h"
56 #include "rpvar.h"
58 static const char RocketPortVersion[] = "3.02";
60 static Byte_t RData[RDATASIZE] =
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
82 static Byte_t RRegData[RREGDATASIZE]=
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 */
99 Byte_t rp_sBitMapClrTbl[8] =
101 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
104 Byte_t rp_sBitMapSetTbl[8] =
106 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
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.
121 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
123 Byte_t AiopID; /* ID byte from AIOP */
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);
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.
150 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
152 Word_t x, y;
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);
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.
180 No context switches are allowed while executing this function.
182 int sInitChan( CONTROLLER_T *CtlP,
183 CHANNEL_T *ChP,
184 int AiopNum,
185 int ChanNum)
187 int i, ChOff;
188 Byte_t *ChR;
189 static Byte_t R[4];
191 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
192 return(FALSE); /* exceeds num chans in AIOP */
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;
201 /* Initialize the channel from the RData array */
202 for(i=0; i < RDATASIZE; i+=4)
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]));
211 ChR = ChP->R;
212 for(i=0; i < RREGDATASIZE; i+=4)
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];
220 /* Indexed registers */
221 ChOff = (Word_t)ChanNum * 0x1000;
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]);
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]);
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]);
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]);
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]);
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]);
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]);
265 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
266 ChP->TxFIFO = ChOff + _TX_FIFO;
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;
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 */
290 crit_exit();
291 return(TRUE);
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
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.
304 Warnings: No context switches are allowed while executing this function.
306 Do not leave the receive processor stopped for more than one
307 character time.
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.
312 void sStopRxProcessor(CHANNEL_T *ChP)
314 Byte_t R[4];
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();
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.
339 void sFlushRxFIFO(CHANNEL_T *ChP)
341 int i;
342 Byte_t Ch; /* channel number within AIOP */
343 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
345 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
346 return; /* don't need to flush */
348 crit_enter();
349 RxFIFOEnabled = FALSE;
350 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
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 */
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();
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.
384 void sFlushTxFIFO(CHANNEL_T *ChP)
386 int i;
387 Byte_t Ch; /* channel number within AIOP */
388 int TxEnabled; /* TRUE if transmitter enabled */
390 crit_enter();
391 if(sGetTxCnt(ChP) == 0) { /* Tx FIFO empty */
392 crit_exit();
393 return; /* don't need to flush */
396 TxEnabled = FALSE;
397 if(ChP->TxControl[3] & TX_ENABLE)
399 TxEnabled = TRUE;
400 sDisTransmit(ChP); /* disable transmitter */
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();
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
423 Return: int: 1 if the bytes is successfully written, otherwise 0.
425 Comments: The priority byte is transmitted before any data in the Tx FIFO.
427 Warnings: No context switches are allowed while executing this function.
429 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
431 Byte_t DWBuf[4]; /* buffer for double word writes */
432 Word_t *WordPtr; /* must be far because Win SS != DS */
434 crit_enter();
435 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
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 */
443 WordPtr = (Word_t *)(&DWBuf[0]);
444 *WordPtr = ChP->TxPrioBuf; /* data byte address */
446 DWBuf[2] = Data; /* data byte value */
447 rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
449 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
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 */
455 else /* write it to Tx FIFO */
457 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
459 crit_exit();
460 return(1); /* 1 byte sent */
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().
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.
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().
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.
495 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
497 Byte_t Mask; /* Interrupt Mask Register */
499 ChP->RxControl[2] |=
500 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
502 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
504 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
506 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
508 if(Flags & CHANINT_EN)
510 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
511 rp_writech1(ChP,_INT_MASK,Mask);
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().
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.
540 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
542 Byte_t Mask; /* Interrupt Mask Register */
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]);
550 if(Flags & CHANINT_EN)
552 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
553 rp_writech1(ChP,_INT_MASK,Mask);
557 /*********************************************************************
558 Begin FreeBsd-specific driver code
559 **********************************************************************/
561 static timeout_t rpdtrwakeup;
563 static d_open_t rpopen;
564 static d_close_t rpclose;
565 static d_write_t rpwrite;
566 static d_ioctl_t rpioctl;
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
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;
585 static int rp_num_ports[4]; /* Number of ports on each controller */
587 #define POLL_INTERVAL 1
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)
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)
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])
609 * The top-level routines begin here
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);
619 * NOTE: Must be called with tty_token held
621 static void
622 rp_do_receive(struct rp_port *rp, struct tty *tp,
623 CHANNEL_t *cp, unsigned int ChanStatus)
625 unsigned int CharNStat;
626 int ToRecv, wRecv, ch, ttynocopy;
628 ASSERT_LWKT_TOKEN_HELD(&tty_token);
629 ToRecv = sGetRxCnt(cp);
630 if(ToRecv == 0)
631 return;
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)
638 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
639 if(!(ChanStatus & STATMODE)) {
640 ChanStatus |= STATMODE;
641 sEnRxStatusMode(cp);
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.
649 if(ChanStatus & STATMODE) {
650 while(ToRecv) {
651 if(tp->t_state & TS_TBLOCK) {
652 break;
654 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
655 ch = CharNStat & 0xff;
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++;
664 (*linesw[tp->t_line].l_rint)(ch, tp);
665 ToRecv--;
668 After emtying FIFO in status mode, turn off status mode
671 if(sGetRxCnt(cp) == 0) {
672 sDisRxStatusMode(cp);
674 } else {
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).
682 ToRecv = sGetRxCnt(cp);
683 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
684 if ( ToRecv > RXFIFO_SIZE ) {
685 ToRecv = RXFIFO_SIZE;
687 wRecv = ToRecv >> 1;
688 if ( wRecv ) {
689 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
691 if ( ToRecv & 1 ) {
692 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
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;
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--;
715 * NOTE: Must be called with tty_token held
717 static void
718 rp_handle_port(struct rp_port *rp)
720 CHANNEL_t *cp;
721 struct tty *tp;
722 unsigned int IntMask, ChanStatus;
724 ASSERT_LWKT_TOKEN_HELD(&tty_token);
726 if(!rp)
727 return;
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);
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);
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);
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);
760 static void rp_do_poll(void *not_used)
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;
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);
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);
800 if(rp_num_ports_open)
801 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
802 lwkt_reltoken(&tty_token);
806 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
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;
816 lwkt_gettoken(&tty_token);
817 unit = device_get_unit(ctlp->dev);
819 kprintf("RocketPort%d (Version %s) %d ports.\n", unit,
820 RocketPortVersion, num_ports);
821 rp_num_ports[unit] = num_ports;
823 ctlp->rp = rp = kmalloc(sizeof(struct rp_port) * num_ports,
824 M_TTYS, M_WAITOK | M_ZERO);
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;
830 ctlp->tty = tty = kmalloc(sizeof(struct tty) * num_ports,
831 M_TTYS, M_WAITOK | M_ZERO);
833 crit_enter();
834 rp_addr(unit) = rp;
835 crit_exit();
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);
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;
869 tty->t_line = 0;
870 /* tty->t_termios = deftermios;
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);
880 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
881 rp->it_out = rp->it_in;
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;
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;
898 rp_ndevs++;
899 lwkt_reltoken(&tty_token);
900 return (0);
902 nogo:
903 rp_releaseresource(ctlp);
904 lwkt_reltoken(&tty_token);
905 return (retval);
908 void
909 rp_releaseresource(CONTROLLER_t *ctlp)
911 int i, unit;
913 lwkt_gettoken(&tty_token);
914 unit = device_get_unit(ctlp->dev);
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;
928 if (ctlp->tty != NULL) {
929 kfree(ctlp->tty, M_DEVBUF);
930 ctlp->tty = NULL;
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);
939 rpopen(struct dev_open_args *ap)
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;
948 lwkt_gettoken(&tty_token);
949 if (!rp_initialized) {
950 rp_initialized = 1;
951 callout_init_mp(&rp_poll_ch);
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);
962 if(IS_CONTROL(dev)) {
963 lwkt_reltoken(&tty_token);
964 return(0);
966 rp = rp_addr(unit) + port;
967 /* rp->rp_tty = &rp_tty[rp->rp_port];
969 callout_init_mp(&rp->wakeup_callout);
970 tp = rp->rp_tty;
971 dev->si_tty = tp;
973 crit_enter();
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;
982 if(tp->t_state & TS_ISOPEN) {
983 if(IS_CALLOUT(dev)) {
984 if(!rp->active_out) {
985 error = EBUSY;
986 goto out;
988 } else {
989 if(rp->active_out) {
990 if(ap->a_oflags & O_NONBLOCK) {
991 error = EBUSY;
992 goto out;
994 error = tsleep(&rp->active_out,
995 PCATCH, "rpbi", 0);
996 if(error != 0)
997 goto out;
998 goto open_top;
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;
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);
1030 sEnInterrupts(&rp->rp_channel,
1031 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1032 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1034 sDisRxStatusMode(&rp->rp_channel);
1035 sClrTxXOFF(&rp->rp_channel);
1037 /* sDisRTSFlowCtl(&rp->rp_channel);
1038 sDisCTSFlowCtl(&rp->rp_channel);
1040 sDisTxSoftFlowCtl(&rp->rp_channel);
1042 sStartRxProcessor(&rp->rp_channel);
1044 sEnRxFIFO(&rp->rp_channel);
1045 sEnTransmit(&rp->rp_channel);
1047 /* sSetDTR(&rp->rp_channel);
1048 sSetRTS(&rp->rp_channel);
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);
1060 rp_num_ports_open++;
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);
1071 if(rp_num_ports_open == 1)
1072 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
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;
1085 error = (*linesw[tp->t_line].l_open)(dev, tp);
1087 rp_disc_optim(tp, &tp->t_termios);
1088 if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1089 rp->active_out = TRUE;
1091 /* if(rp_num_ports_open == 1)
1092 callout_reset(&rp_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1094 out:
1095 crit_exit();
1096 if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1097 rphardclose(rp);
1099 out2:
1100 if (error == 0)
1101 device_busy(rp->rp_ctlp->dev);
1102 lwkt_reltoken(&tty_token);
1103 return(error);
1107 rpclose(struct dev_close_args *ap)
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;
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 */
1120 if(IS_CONTROL(dev)) {
1121 lwkt_reltoken(&tty_token);
1122 return(0);
1124 rp = rp_addr(unit) + port;
1125 tp = rp->rp_tty;
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);
1133 tp->t_state &= ~TS_BUSY;
1134 ttyclose(tp);
1136 crit_exit();
1138 device_unbusy(rp->rp_ctlp->dev);
1140 lwkt_reltoken(&tty_token);
1141 return(0);
1145 * NOTE: Must be called with tty_token held
1147 static void
1148 rphardclose(struct rp_port *rp)
1150 struct tty *tp;
1151 CHANNEL_t *cp;
1153 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1154 cp = &rp->rp_channel;
1155 tp = rp->rp_tty;
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);
1166 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1167 sClrDTR(cp);
1169 if(IS_CALLOUT(tp->t_dev)) {
1170 sClrDTR(cp);
1172 if(rp->dtr_wait != 0) {
1173 callout_reset(&rp->wakeup_callout, rp->dtr_wait,
1174 rpdtrwakeup, rp);
1175 rp->state |= ~SET_DTR;
1178 rp->active_out = FALSE;
1179 wakeup(&rp->active_out);
1180 wakeup(TSA_CARR_ON(tp));
1183 static
1185 rpwrite(struct dev_write_args *ap)
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 */
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 */
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);
1211 error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
1212 lwkt_reltoken(&tty_token);
1213 return error;
1216 static void
1217 rpdtrwakeup(void *chan)
1219 struct rp_port *rp;
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);
1229 rpioctl(struct dev_ioctl_args *ap)
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;
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;
1247 if(IS_CONTROL(dev)) {
1248 struct termios *ct;
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 */
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);
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);
1289 tp = rp->rp_tty;
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;
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;
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);
1320 crit_enter();
1322 flags = rp->rp_channel.TxControl[3];
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);
1332 switch(cmd) {
1333 case TIOCSBRK:
1334 sSendBreak(&rp->rp_channel);
1335 break;
1337 case TIOCCBRK:
1338 sClrBreak(&rp->rp_channel);
1339 break;
1341 case TIOCSDTR:
1342 sSetDTR(&rp->rp_channel);
1343 sSetRTS(&rp->rp_channel);
1344 break;
1346 case TIOCCDTR:
1347 sClrDTR(&rp->rp_channel);
1348 break;
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;
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));
1397 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1399 result |= TIOCM_RTS;
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);
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;
1421 crit_exit();
1422 lwkt_reltoken(&tty_token);
1423 return(0);
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}
1438 static int
1439 rpparam(struct tty *tp, struct termios *t)
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
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 */
1455 unit = minor_to_unit[mynor];
1456 rp = rp_addr(unit) + port;
1457 cp = &rp->rp_channel;
1458 crit_enter();
1460 cflag = t->c_cflag;
1461 #ifdef RPCLOCAL
1462 devshift = umynor / 32;
1463 devshift = 1 << devshift;
1464 if ( devshift & RPCLOCAL ) {
1465 cflag |= CLOCAL;
1467 #endif
1468 iflag = t->c_iflag;
1469 oflag = t->c_oflag;
1470 lflag = t->c_lflag;
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);
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;
1486 if(t->c_ospeed == 0) {
1487 sClrDTR(cp);
1488 crit_exit();
1489 lwkt_reltoken(&tty_token);
1490 return(0);
1492 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1494 /* Set baud rate ----- we only pay attention to ispeed */
1495 sSetDTR(cp);
1496 sSetRTS(cp);
1497 sSetBaud(cp, ospeed);
1499 if(cflag & CSTOPB) {
1500 sSetStop2(cp);
1501 } else {
1502 sSetStop1(cp);
1505 if(cflag & PARENB) {
1506 sEnParity(cp);
1507 if(cflag & PARODD) {
1508 sSetOddParity(cp);
1509 } else {
1510 sSetEvenParity(cp);
1513 else {
1514 sDisParity(cp);
1516 if((cflag & CSIZE) == CS8) {
1517 sSetData8(cp);
1518 rp->rp_imask = 0xFF;
1519 } else {
1520 sSetData7(cp);
1521 rp->rp_imask = 0x7F;
1524 if(iflag & ISTRIP) {
1525 rp->rp_imask &= 0x7F;
1528 if(cflag & CLOCAL) {
1529 rp->rp_intmask &= ~DELTA_CD;
1530 } else {
1531 rp->rp_intmask |= DELTA_CD;
1534 /* Put flow control stuff here */
1536 if(cflag & CCTS_OFLOW) {
1537 sEnCTSFlowCtl(cp);
1538 } else {
1539 sDisCTSFlowCtl(cp);
1542 if(cflag & CRTS_IFLOW) {
1543 rp->rp_rts_iflow = 1;
1544 } else {
1545 rp->rp_rts_iflow = 0;
1548 if(cflag & CRTS_IFLOW) {
1549 sEnRTSFlowCtl(cp);
1550 } else {
1551 sDisRTSFlowCtl(cp);
1553 rp_disc_optim(tp, t);
1555 if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1556 tp->t_state |= TS_CARR_ON;
1557 wakeup(TSA_CARR_ON(tp));
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
1567 crit_exit();
1569 lwkt_reltoken(&tty_token);
1570 return(0);
1573 static void
1574 rp_disc_optim(struct tty *tp, struct termios *t)
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);
1589 static void
1590 rpstart(struct tty *tp)
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;
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();
1609 if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1610 ttwwakeup(tp);
1611 crit_exit();
1612 lwkt_reltoken(&tty_token);
1613 return;
1615 if(rp->rp_xmit_stopped) {
1616 sEnTransmit(cp);
1617 rp->rp_xmit_stopped = 0;
1619 count = sGetTxCnt(cp);
1621 if(tp->t_outq.c_cc == 0) {
1622 if((tp->t_state & TS_BUSY) && (count == 0)) {
1623 tp->t_state &= ~TS_BUSY;
1625 ttwwakeup(tp);
1626 crit_exit();
1627 lwkt_reltoken(&tty_token);
1628 return;
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);
1639 if ( count & 1 ) {
1640 rp_writech1(cp, sGetTxRxDataIO(cp),
1641 ((unsigned char *)(rp->TxBuf))[(count-1)]);
1644 rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1646 ttwwakeup(tp);
1647 crit_exit();
1648 lwkt_reltoken(&tty_token);
1651 static
1652 void
1653 rpstop(struct tty *tp, int flag)
1655 struct rp_port *rp;
1656 CHANNEL_t *cp;
1657 int unit, mynor, port, umynor; /* SG */
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;
1667 crit_enter();
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;
1679 crit_exit();
1680 rpstart(tp);
1681 lwkt_reltoken(&tty_token);