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