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