proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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 $
dadab5e9 33 * $DragonFly: src/sys/dev/serial/rp/rp.c,v 1.4 2003/06/25 03:55:48 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>
53
54#define ROCKET_C
55#include <dev/rp/rpreg.h>
56#include <dev/rp/rpvar.h>
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
574struct cdevsw rp_cdevsw = {
575 /* open */ rpopen,
576 /* close */ rpclose,
577 /* read */ ttyread,
578 /* write */ rpwrite,
579 /* ioctl */ rpioctl,
580 /* poll */ ttypoll,
581 /* mmap */ nommap,
582 /* strategy */ nostrategy,
583 /* name */ "rp",
584 /* maj */ CDEV_MAJOR,
585 /* dump */ nodump,
586 /* psize */ nopsize,
587 /* flags */ D_TTY,
588};
589
590static int rp_num_ports_open = 0;
591static int rp_ndevs = 0;
592static int minor_to_unit[128];
593
594static int rp_num_ports[4]; /* Number of ports on each controller */
595
596#define _INLINE_ __inline
597#define POLL_INTERVAL 1
598
599#define CALLOUT_MASK 0x80
600#define CONTROL_MASK 0x60
601#define CONTROL_INIT_STATE 0x20
602#define CONTROL_LOCK_STATE 0x40
603#define DEV_UNIT(dev) (MINOR_TO_UNIT(minor(dev))
604#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
605#define MINOR_MAGIC(dev) ((minor(dev)) & ~MINOR_MAGIC_MASK)
606#define IS_CALLOUT(dev) (minor(dev) & CALLOUT_MASK)
607#define IS_CONTROL(dev) (minor(dev) & CONTROL_MASK)
608
609#define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
610#define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
611#define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
612
613static struct rp_port *p_rp_addr[4];
614static struct rp_port *p_rp_table[MAX_RP_PORTS];
615#define rp_addr(unit) (p_rp_addr[unit])
616#define rp_table(port) (p_rp_table[port])
617
618/*
619 * The top-level routines begin here
620 */
621
622static int rpparam __P((struct tty *, struct termios *));
623static void rpstart __P((struct tty *));
624static void rpstop __P((struct tty *, int));
625static void rphardclose __P((struct rp_port *));
626static void rp_disc_optim __P((struct tty *tp, struct termios *t));
627
628static _INLINE_ void rp_do_receive(struct rp_port *rp, struct tty *tp,
629 CHANNEL_t *cp, unsigned int ChanStatus)
630{
631 int spl;
632 unsigned int CharNStat;
633 int ToRecv, wRecv, ch, ttynocopy;
634
635 ToRecv = sGetRxCnt(cp);
636 if(ToRecv == 0)
637 return;
638
639/* If status indicates there are errored characters in the
640 FIFO, then enter status mode (a word in FIFO holds
641 characters and status)
642*/
643
644 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
645 if(!(ChanStatus & STATMODE)) {
646 ChanStatus |= STATMODE;
647 sEnRxStatusMode(cp);
648 }
649 }
650/*
651 if we previously entered status mode then read down the
652 FIFO one word at a time, pulling apart the character and
653 the status. Update error counters depending on status.
654*/
655 if(ChanStatus & STATMODE) {
656 while(ToRecv) {
657 if(tp->t_state & TS_TBLOCK) {
658 break;
659 }
660 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
661 ch = CharNStat & 0xff;
662
663 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
664 ch |= TTY_FE;
665 else if (CharNStat & STMPARITYH)
666 ch |= TTY_PE;
667 else if (CharNStat & STMRCVROVRH)
668 rp->rp_overflows++;
669
670 (*linesw[tp->t_line].l_rint)(ch, tp);
671 ToRecv--;
672 }
673/*
674 After emtying FIFO in status mode, turn off status mode
675*/
676
677 if(sGetRxCnt(cp) == 0) {
678 sDisRxStatusMode(cp);
679 }
680 } else {
681 /*
682 * Avoid the grotesquely inefficient lineswitch routine
683 * (ttyinput) in "raw" mode. It usually takes about 450
684 * instructions (that's without canonical processing or echo!).
685 * slinput is reasonably fast (usually 40 instructions plus
686 * call overhead).
687 */
688 ToRecv = sGetRxCnt(cp);
689 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
690 if ( ToRecv > RXFIFO_SIZE ) {
691 ToRecv = RXFIFO_SIZE;
692 }
693 wRecv = ToRecv >> 1;
694 if ( wRecv ) {
695 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
696 }
697 if ( ToRecv & 1 ) {
698 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
699 }
700 tk_nin += ToRecv;
701 tk_rawcc += ToRecv;
702 tp->t_rawcc += ToRecv;
703 ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
704 ttwakeup(tp);
705 } else {
706 while (ToRecv) {
707 if(tp->t_state & TS_TBLOCK) {
708 break;
709 }
710 ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
711 spl = spltty();
712 (*linesw[tp->t_line].l_rint)(ch, tp);
713 splx(spl);
714 ToRecv--;
715 }
716 }
717 }
718}
719
720static _INLINE_ void rp_handle_port(struct rp_port *rp)
721{
722 CHANNEL_t *cp;
723 struct tty *tp;
724 unsigned int IntMask, ChanStatus;
725
726 if(!rp)
727 return;
728
729 cp = &rp->rp_channel;
730 tp = rp->rp_tty;
731 IntMask = sGetChanIntID(cp);
732 IntMask = IntMask & rp->rp_intmask;
733 ChanStatus = sGetChanStatus(cp);
734 if(IntMask & RXF_TRIG)
735 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
736 rp_do_receive(rp, tp, cp, ChanStatus);
737 }
738 if(IntMask & DELTA_CD) {
739 if(ChanStatus & CD_ACT) {
740 if(!(tp->t_state & TS_CARR_ON) ) {
741 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
742 }
743 } else {
744 if((tp->t_state & TS_CARR_ON)) {
745 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
746 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
747 rphardclose(rp);
748 }
749 }
750 }
751 }
752/* oldcts = rp->rp_cts;
753 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
754 if(oldcts != rp->rp_cts) {
755 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
756 }
757*/
758}
759
760static void rp_do_poll(void *not_used)
761{
762 CONTROLLER_t *ctl;
763 struct rp_port *rp;
764 struct tty *tp;
765 int unit, aiop, ch, line, count;
766 unsigned char CtlMask, AiopMask;
767
768 for(unit = 0; unit < rp_ndevs; unit++) {
769 rp = rp_addr(unit);
770 ctl = rp->rp_ctlp;
771 CtlMask = ctl->ctlmask(ctl);
772 for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
773 if(CtlMask & 1) {
774 AiopMask = sGetAiopIntStatus(ctl, aiop);
775 for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
776 if(AiopMask & 1) {
777 line = (unit << 5) | (aiop << 3) | ch;
778 rp = rp_table(line);
779 rp_handle_port(rp);
780 }
781 }
782 }
783 }
784
785 for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
786 line++, rp++) {
787 tp = rp->rp_tty;
788 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
789 count = sGetTxCnt(&rp->rp_channel);
790 if(count == 0)
791 tp->t_state &= ~(TS_BUSY);
792 if(!(tp->t_state & TS_TTSTOP) &&
793 (count <= rp->rp_restart)) {
794 (*linesw[tp->t_line].l_start)(tp);
795 }
796 }
797 }
798 }
799 if(rp_num_ports_open)
800 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
801}
802
803int
804rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
805{
806 int oldspl, unit;
807 int num_chan;
808 int aiop, chan, port;
809 int ChanStatus, line, i, count;
810 int retval;
811 struct rp_port *rp;
812 struct tty *tty;
813 dev_t *dev_nodes;
814
815 unit = device_get_unit(ctlp->dev);
816
817 printf("RocketPort%d (Version %s) %d ports.\n", unit,
818 RocketPortVersion, num_ports);
819 rp_num_ports[unit] = num_ports;
820
821 ctlp->rp = rp = (struct rp_port *)
822 malloc(sizeof(struct rp_port) * num_ports, M_TTYS, M_NOWAIT);
823 if (rp == NULL) {
824 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
825 retval = ENOMEM;
826 goto nogo;
827 }
828
829 count = unit * 32; /* board times max ports per card SG */
830 for(i=count;i < (count + rp_num_ports[unit]);i++)
831 minor_to_unit[i] = unit;
832
833 bzero(rp, sizeof(struct rp_port) * num_ports);
834 ctlp->tty = tty = (struct tty *)
835 malloc(sizeof(struct tty) * num_ports, M_TTYS,
836 M_NOWAIT | M_ZERO);
837 if(tty == NULL) {
838 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc tty structures.\n");
839 retval = ENOMEM;
840 goto nogo;
841 }
842
843 oldspl = spltty();
844 rp_addr(unit) = rp;
845 splx(oldspl);
846
847 dev_nodes = ctlp->dev_nodes = malloc(sizeof(*(ctlp->dev_nodes)) * rp_num_ports[unit] * 6, M_DEVBUF, M_NOWAIT | M_ZERO);
848 if(ctlp->dev_nodes == NULL) {
849 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc device node structures.\n");
850 retval = ENOMEM;
851 goto nogo;
852 }
853
854 for (i = 0 ; i < rp_num_ports[unit] ; i++) {
855 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i,
856 UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
857 i <= 9 ? '0' + i : 'a' + i - 10);
858 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x20,
859 UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
860 i <= 9 ? '0' + i : 'a' + i - 10);
861 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x40,
862 UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
863 i <= 9 ? '0' + i : 'a' + i - 10);
864 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x80,
865 UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
866 i <= 9 ? '0' + i : 'a' + i - 10);
867 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xa0,
868 UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
869 i <= 9 ? '0' + i : 'a' + i - 10);
870 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xc0,
871 UID_ROOT, GID_WHEEL, 0666, "cualR%c",
872 i <= 9 ? '0' + i : 'a' + i - 10);
873 }
874
875 port = 0;
876 for(aiop=0; aiop < num_aiops; aiop++) {
877 num_chan = sGetAiopNumChan(ctlp, aiop);
878 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
879 rp->rp_tty = tty;
880 rp->rp_port = port;
881 rp->rp_ctlp = ctlp;
882 rp->rp_unit = unit;
883 rp->rp_chan = chan;
884 rp->rp_aiop = aiop;
885
886 tty->t_line = 0;
887 /* tty->t_termios = deftermios;
888 */
889 rp->dtr_wait = 3 * hz;
890 rp->it_in.c_iflag = 0;
891 rp->it_in.c_oflag = 0;
892 rp->it_in.c_cflag = TTYDEF_CFLAG;
893 rp->it_in.c_lflag = 0;
894 termioschars(&rp->it_in);
895 /* termioschars(&tty->t_termios);
896 */
897 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
898 rp->it_out = rp->it_in;
899
900 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
901 DELTA_CD | DELTA_CTS | DELTA_DSR;
902#if notdef
903 ChanStatus = sGetChanStatus(&rp->rp_channel);
904#endif /* notdef */
905 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
906 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
907 unit, aiop, chan);
908 retval = ENXIO;
909 goto nogo;
910 }
911 ChanStatus = sGetChanStatus(&rp->rp_channel);
912 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
913 line = (unit << 5) | (aiop << 3) | chan;
914 rp_table(line) = rp;
915 }
916 }
917
918 rp_ndevs++;
919 return (0);
920
921nogo:
922 rp_releaseresource(ctlp);
923
924 return (retval);
925}
926
927void
928rp_releaseresource(CONTROLLER_t *ctlp)
929{
930 int i, s, unit;
931
932 unit = device_get_unit(ctlp->dev);
933
934 if (ctlp->rp != NULL) {
935 s = spltty();
936 for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
937 if (p_rp_addr[i] == ctlp->rp)
938 p_rp_addr[i] = NULL;
939 for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
940 if (p_rp_table[i] == ctlp->rp)
941 p_rp_table[i] = NULL;
942 splx(s);
943 free(ctlp->rp, M_DEVBUF);
944 ctlp->rp = NULL;
945 }
946 if (ctlp->tty != NULL) {
947 free(ctlp->tty, M_DEVBUF);
948 ctlp->tty = NULL;
949 }
950 if (ctlp->dev != NULL) {
951 for (i = 0 ; i < rp_num_ports[unit] * 6 ; i++)
952 destroy_dev(ctlp->dev_nodes[i]);
953 free(ctlp->dev_nodes, M_DEVBUF);
954 ctlp->dev = NULL;
955 }
956}
957
958int
41c20dac 959rpopen(dev_t dev, int flag, int mode, d_thread_t *td)
984263bc
MD
960{
961 struct rp_port *rp;
962 int unit, port, mynor, umynor, flags; /* SG */
963 struct tty *tp;
964 int oldspl, error;
965 unsigned int IntMask, ChanStatus;
984263bc
MD
966
967 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
968 port = (minor(dev) & 0x1f); /* SG */
969 mynor = (port + umynor); /* SG */
970 unit = minor_to_unit[mynor];
971 if (rp_addr(unit) == NULL)
972 return (ENXIO);
973 if(IS_CONTROL(dev))
974 return(0);
975 rp = rp_addr(unit) + port;
976/* rp->rp_tty = &rp_tty[rp->rp_port];
977*/
978 tp = rp->rp_tty;
979 dev->si_tty = tp;
980
981 oldspl = spltty();
982
983open_top:
984 while(rp->state & ~SET_DTR) {
985 error = tsleep(&rp->dtr_wait, TTIPRI | PCATCH, "rpdtr", 0);
986 if(error != 0)
987 goto out;
988 }
989
990 if(tp->t_state & TS_ISOPEN) {
991 if(IS_CALLOUT(dev)) {
992 if(!rp->active_out) {
993 error = EBUSY;
994 goto out;
995 }
996 } else {
997 if(rp->active_out) {
998 if(flag & O_NONBLOCK) {
999 error = EBUSY;
1000 goto out;
1001 }
1002 error = tsleep(&rp->active_out,
1003 TTIPRI | PCATCH, "rpbi", 0);
1004 if(error != 0)
1005 goto out;
1006 goto open_top;
1007 }
1008 }
dadab5e9 1009 if(tp->t_state & TS_XCLUDE && suser(td) != 0) {
984263bc
MD
1010 splx(oldspl);
1011 error = EBUSY;
1012 goto out2;
1013 }
1014 }
1015 else {
1016 tp->t_dev = dev;
1017 tp->t_param = rpparam;
1018 tp->t_oproc = rpstart;
1019 tp->t_stop = rpstop;
1020 tp->t_line = 0;
1021 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1022 tp->t_ififosize = 512;
1023 tp->t_ispeedwat = (speed_t)-1;
1024 tp->t_ospeedwat = (speed_t)-1;
1025 flags = 0;
1026 flags |= SET_RTS;
1027 flags |= SET_DTR;
1028 rp->rp_channel.TxControl[3] =
1029 ((rp->rp_channel.TxControl[3]
1030 & ~(SET_RTS | SET_DTR)) | flags);
1031 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1032 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1033 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1034 sDisRxStatusMode(&rp->rp_channel);
1035 sFlushRxFIFO(&rp->rp_channel);
1036 sFlushTxFIFO(&rp->rp_channel);
1037
1038 sEnInterrupts(&rp->rp_channel,
1039 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1040 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1041
1042 sDisRxStatusMode(&rp->rp_channel);
1043 sClrTxXOFF(&rp->rp_channel);
1044
1045/* sDisRTSFlowCtl(&rp->rp_channel);
1046 sDisCTSFlowCtl(&rp->rp_channel);
1047*/
1048 sDisTxSoftFlowCtl(&rp->rp_channel);
1049
1050 sStartRxProcessor(&rp->rp_channel);
1051
1052 sEnRxFIFO(&rp->rp_channel);
1053 sEnTransmit(&rp->rp_channel);
1054
1055/* sSetDTR(&rp->rp_channel);
1056 sSetRTS(&rp->rp_channel);
1057*/
1058
1059 ++rp->wopeners;
1060 error = rpparam(tp, &tp->t_termios);
1061 --rp->wopeners;
1062 if(error != 0) {
1063 splx(oldspl);
1064 return(error);
1065 }
1066
1067 rp_num_ports_open++;
1068
1069 IntMask = sGetChanIntID(&rp->rp_channel);
1070 IntMask = IntMask & rp->rp_intmask;
1071 ChanStatus = sGetChanStatus(&rp->rp_channel);
1072 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1073 if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1074 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1075 }
1076 }
1077
1078 if(rp_num_ports_open == 1)
1079 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
1080
1081 }
1082
1083 if(!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1084 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1085 ++rp->wopeners;
1086 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH,
1087 "rpdcd", 0);
1088 --rp->wopeners;
1089 if(error != 0)
1090 goto out;
1091 goto open_top;
1092 }
1093 error = (*linesw[tp->t_line].l_open)(dev, tp);
1094
1095 rp_disc_optim(tp, &tp->t_termios);
1096 if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1097 rp->active_out = TRUE;
1098
1099/* if(rp_num_ports_open == 1)
1100 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
1101*/
1102out:
1103 splx(oldspl);
1104 if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1105 rphardclose(rp);
1106 }
1107out2:
1108 if (error == 0)
1109 device_busy(rp->rp_ctlp->dev);
1110 return(error);
1111}
1112
1113int
41c20dac 1114rpclose(dev_t dev, int flag, int mode, d_thread_t *td)
984263bc
MD
1115{
1116 int oldspl, unit, mynor, umynor, port; /* SG */
1117 struct rp_port *rp;
1118 struct tty *tp;
1119 CHANNEL_t *cp;
1120
1121 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1122 port = (minor(dev) & 0x1f); /* SG */
1123 mynor = (port + umynor); /* SG */
1124 unit = minor_to_unit[mynor]; /* SG */
1125
1126 if(IS_CONTROL(dev))
1127 return(0);
1128 rp = rp_addr(unit) + port;
1129 cp = &rp->rp_channel;
1130 tp = rp->rp_tty;
1131
1132 oldspl = spltty();
1133 (*linesw[tp->t_line].l_close)(tp, flag);
1134 rp_disc_optim(tp, &tp->t_termios);
1135 rpstop(tp, FREAD | FWRITE);
1136 rphardclose(rp);
1137
1138 tp->t_state &= ~TS_BUSY;
1139 ttyclose(tp);
1140
1141 splx(oldspl);
1142
1143 device_unbusy(rp->rp_ctlp->dev);
1144
1145 return(0);
1146}
1147
1148static void
1149rphardclose(struct rp_port *rp)
1150{
1151 int mynor;
1152 struct tty *tp;
1153 CHANNEL_t *cp;
1154
1155 cp = &rp->rp_channel;
1156 tp = rp->rp_tty;
1157 mynor = MINOR_MAGIC(tp->t_dev);
1158
1159 sFlushRxFIFO(cp);
1160 sFlushTxFIFO(cp);
1161 sDisTransmit(cp);
1162 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1163 sDisRTSFlowCtl(cp);
1164 sDisCTSFlowCtl(cp);
1165 sDisTxSoftFlowCtl(cp);
1166 sClrTxXOFF(cp);
1167
1168 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1169 sClrDTR(cp);
1170 }
1171 if(IS_CALLOUT(tp->t_dev)) {
1172 sClrDTR(cp);
1173 }
1174 if(rp->dtr_wait != 0) {
1175 timeout(rpdtrwakeup, rp, rp->dtr_wait);
1176 rp->state |= ~SET_DTR;
1177 }
1178
1179 rp->active_out = FALSE;
1180 wakeup(&rp->active_out);
1181 wakeup(TSA_CARR_ON(tp));
1182}
1183
1184static
1185int
1186rpwrite(dev, uio, flag)
1187 dev_t dev;
1188 struct uio *uio;
1189 int flag;
1190{
1191 struct rp_port *rp;
1192 struct tty *tp;
1193 int unit, mynor, port, umynor, error = 0; /* SG */
1194
1195 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1196 port = (minor(dev) & 0x1f); /* SG */
1197 mynor = (port + umynor); /* SG */
1198 unit = minor_to_unit[mynor]; /* SG */
1199
1200 if(IS_CONTROL(dev))
1201 return(ENODEV);
1202 rp = rp_addr(unit) + port;
1203 tp = rp->rp_tty;
1204 while(rp->rp_disable_writes) {
1205 rp->rp_waiting = 1;
1206 error = ttysleep(tp, (caddr_t)rp, TTOPRI|PCATCH, "rp_write", 0);
1207 if (error)
1208 return(error);
1209 }
1210
1211 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1212 return error;
1213}
1214
1215static void
1216rpdtrwakeup(void *chan)
1217{
1218 struct rp_port *rp;
1219
1220 rp = (struct rp_port *)chan;
1221 rp->state &= SET_DTR;
1222 wakeup(&rp->dtr_wait);
1223}
1224
1225int
41c20dac 1226rpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td)
984263bc
MD
1227{
1228 struct rp_port *rp;
1229 CHANNEL_t *cp;
1230 struct tty *tp;
1231 int unit, mynor, port, umynor; /* SG */
1232 int oldspl;
1233 int error = 0;
1234 int arg, flags, result, ChanStatus;
1235 struct termios *t;
1236
1237 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1238 port = (minor(dev) & 0x1f); /* SG */
1239 mynor = (port + umynor); /* SG */
1240 unit = minor_to_unit[mynor];
1241 rp = rp_addr(unit) + port;
1242
1243 if(IS_CONTROL(dev)) {
1244 struct termios *ct;
1245
1246 switch (IS_CONTROL(dev)) {
1247 case CONTROL_INIT_STATE:
1248 ct = IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1249 break;
1250 case CONTROL_LOCK_STATE:
1251 ct = IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1252 break;
1253 default:
1254 return(ENODEV); /* /dev/nodev */
1255 }
1256 switch (cmd) {
1257 case TIOCSETA:
dadab5e9 1258 error = suser(td);
984263bc
MD
1259 if(error != 0)
1260 return(error);
1261 *ct = *(struct termios *)data;
1262 return(0);
1263 case TIOCGETA:
1264 *(struct termios *)data = *ct;
1265 return(0);
1266 case TIOCGETD:
1267 *(int *)data = TTYDISC;
1268 return(0);
1269 case TIOCGWINSZ:
1270 bzero(data, sizeof(struct winsize));
1271 return(0);
1272 default:
1273 return(ENOTTY);
1274 }
1275 }
1276
1277 tp = rp->rp_tty;
1278 cp = &rp->rp_channel;
1279
1280#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1281 term = tp->t_termios;
1282 oldcmd = cmd;
1283 error = ttsetcompat(tp, &cmd, data, &term);
1284 if(error != 0)
1285 return(error);
1286 if(cmd != oldcmd) {
1287 data = (caddr_t)&term;
1288 }
1289#endif
1290 if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1291 int cc;
1292 struct termios *dt = (struct termios *)data;
1293 struct termios *lt = IS_CALLOUT(dev)
1294 ? &rp->lt_out : &rp->lt_in;
1295
1296 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1297 | (dt->c_iflag & ~lt->c_iflag);
1298 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1299 | (dt->c_oflag & ~lt->c_oflag);
1300 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1301 | (dt->c_cflag & ~lt->c_cflag);
1302 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1303 | (dt->c_lflag & ~lt->c_lflag);
1304 for(cc = 0; cc < NCCS; ++cc)
1305 if(lt->c_cc[cc] != 0)
1306 dt->c_cc[cc] = tp->t_cc[cc];
1307 if(lt->c_ispeed != 0)
1308 dt->c_ispeed = tp->t_ispeed;
1309 if(lt->c_ospeed != 0)
1310 dt->c_ospeed = tp->t_ospeed;
1311 }
1312
1313 t = &tp->t_termios;
1314
41c20dac 1315 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
984263bc
MD
1316 if(error != ENOIOCTL) {
1317 return(error);
1318 }
1319 oldspl = spltty();
1320
1321 flags = rp->rp_channel.TxControl[3];
1322
1323 error = ttioctl(tp, cmd, data, flag);
1324 flags = rp->rp_channel.TxControl[3];
1325 rp_disc_optim(tp, &tp->t_termios);
1326 if(error != ENOIOCTL) {
1327 splx(oldspl);
1328 return(error);
1329 }
1330 switch(cmd) {
1331 case TIOCSBRK:
1332 sSendBreak(&rp->rp_channel);
1333 break;
1334
1335 case TIOCCBRK:
1336 sClrBreak(&rp->rp_channel);
1337 break;
1338
1339 case TIOCSDTR:
1340 sSetDTR(&rp->rp_channel);
1341 sSetRTS(&rp->rp_channel);
1342 break;
1343
1344 case TIOCCDTR:
1345 sClrDTR(&rp->rp_channel);
1346 break;
1347
1348 case TIOCMSET:
1349 arg = *(int *) data;
1350 flags = 0;
1351 if(arg & TIOCM_RTS)
1352 flags |= SET_RTS;
1353 if(arg & TIOCM_DTR)
1354 flags |= SET_DTR;
1355 rp->rp_channel.TxControl[3] =
1356 ((rp->rp_channel.TxControl[3]
1357 & ~(SET_RTS | SET_DTR)) | flags);
1358 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1359 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1360 break;
1361 case TIOCMBIS:
1362 arg = *(int *) data;
1363 flags = 0;
1364 if(arg & TIOCM_RTS)
1365 flags |= SET_RTS;
1366 if(arg & TIOCM_DTR)
1367 flags |= SET_DTR;
1368 rp->rp_channel.TxControl[3] |= flags;
1369 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1370 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1371 break;
1372 case TIOCMBIC:
1373 arg = *(int *) data;
1374 flags = 0;
1375 if(arg & TIOCM_RTS)
1376 flags |= SET_RTS;
1377 if(arg & TIOCM_DTR)
1378 flags |= SET_DTR;
1379 rp->rp_channel.TxControl[3] &= ~flags;
1380 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1381 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1382 break;
1383
1384
1385 case TIOCMGET:
1386 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1387 flags = rp->rp_channel.TxControl[3];
1388 result = TIOCM_LE; /* always on while open for some reason */
1389 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1390 | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1391 | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1392 | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1393 | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1394
1395 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1396 {
1397 result |= TIOCM_RTS;
1398 }
1399
1400 *(int *)data = result;
1401 break;
1402 case TIOCMSDTRWAIT:
dadab5e9 1403 error = suser(td);
984263bc
MD
1404 if(error != 0) {
1405 splx(oldspl);
1406 return(error);
1407 }
1408 rp->dtr_wait = *(int *)data * hz/100;
1409 break;
1410 case TIOCMGDTRWAIT:
1411 *(int *)data = rp->dtr_wait * 100/hz;
1412 break;
1413 default:
1414 splx(oldspl);
1415 return ENOTTY;
1416 }
1417 splx(oldspl);
1418 return(0);
1419}
1420
1421static struct speedtab baud_table[] = {
1422 {B0, 0}, {B50, BRD50}, {B75, BRD75},
1423 {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
1424 {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
1425 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
1426 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
1427 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
1428 {B57600, BRD57600}, {B76800, BRD76800},
1429 {B115200, BRD115200}, {B230400, BRD230400},
1430 {-1, -1}
1431};
1432
1433static int
1434rpparam(tp, t)
1435 struct tty *tp;
1436 struct termios *t;
1437{
1438 struct rp_port *rp;
1439 CHANNEL_t *cp;
1440 int unit, mynor, port, umynor; /* SG */
1441 int oldspl, cflag, iflag, oflag, lflag;
1442 int ospeed;
1443#ifdef RPCLOCAL
1444 int devshift;
1445#endif
1446
1447
1448 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1449 port = (minor(tp->t_dev) & 0x1f); /* SG */
1450 mynor = (port + umynor); /* SG */
1451
1452 unit = minor_to_unit[mynor];
1453 rp = rp_addr(unit) + port;
1454 cp = &rp->rp_channel;
1455 oldspl = spltty();
1456
1457 cflag = t->c_cflag;
1458#ifdef RPCLOCAL
1459 devshift = umynor / 32;
1460 devshift = 1 << devshift;
1461 if ( devshift & RPCLOCAL ) {
1462 cflag |= CLOCAL;
1463 }
1464#endif
1465 iflag = t->c_iflag;
1466 oflag = t->c_oflag;
1467 lflag = t->c_lflag;
1468
1469 ospeed = ttspeedtab(t->c_ispeed, baud_table);
1470 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1471 return(EINVAL);
1472
1473 tp->t_ispeed = t->c_ispeed;
1474 tp->t_ospeed = t->c_ospeed;
1475 tp->t_cflag = cflag;
1476 tp->t_iflag = iflag;
1477 tp->t_oflag = oflag;
1478 tp->t_lflag = lflag;
1479
1480 if(t->c_ospeed == 0) {
1481 sClrDTR(cp);
1482 return(0);
1483 }
1484 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1485
1486 /* Set baud rate ----- we only pay attention to ispeed */
1487 sSetDTR(cp);
1488 sSetRTS(cp);
1489 sSetBaud(cp, ospeed);
1490
1491 if(cflag & CSTOPB) {
1492 sSetStop2(cp);
1493 } else {
1494 sSetStop1(cp);
1495 }
1496
1497 if(cflag & PARENB) {
1498 sEnParity(cp);
1499 if(cflag & PARODD) {
1500 sSetOddParity(cp);
1501 } else {
1502 sSetEvenParity(cp);
1503 }
1504 }
1505 else {
1506 sDisParity(cp);
1507 }
1508 if((cflag & CSIZE) == CS8) {
1509 sSetData8(cp);
1510 rp->rp_imask = 0xFF;
1511 } else {
1512 sSetData7(cp);
1513 rp->rp_imask = 0x7F;
1514 }
1515
1516 if(iflag & ISTRIP) {
1517 rp->rp_imask &= 0x7F;
1518 }
1519
1520 if(cflag & CLOCAL) {
1521 rp->rp_intmask &= ~DELTA_CD;
1522 } else {
1523 rp->rp_intmask |= DELTA_CD;
1524 }
1525
1526 /* Put flow control stuff here */
1527
1528 if(cflag & CCTS_OFLOW) {
1529 sEnCTSFlowCtl(cp);
1530 } else {
1531 sDisCTSFlowCtl(cp);
1532 }
1533
1534 if(cflag & CRTS_IFLOW) {
1535 rp->rp_rts_iflow = 1;
1536 } else {
1537 rp->rp_rts_iflow = 0;
1538 }
1539
1540 if(cflag & CRTS_IFLOW) {
1541 sEnRTSFlowCtl(cp);
1542 } else {
1543 sDisRTSFlowCtl(cp);
1544 }
1545 rp_disc_optim(tp, t);
1546
1547 if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1548 tp->t_state |= TS_CARR_ON;
1549 wakeup(TSA_CARR_ON(tp));
1550 }
1551
1552/* tp->t_state |= TS_CAN_BYPASS_L_RINT;
1553 flags = rp->rp_channel.TxControl[3];
1554 if(flags & SET_DTR)
1555 else
1556 if(flags & SET_RTS)
1557 else
1558*/
1559 splx(oldspl);
1560
1561 return(0);
1562}
1563
1564static void
1565rp_disc_optim(tp, t)
1566struct tty *tp;
1567struct termios *t;
1568{
1569 if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1570 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1571 &&(!(t->c_iflag & PARMRK)
1572 ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1573 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1574 && linesw[tp->t_line].l_rint == ttyinput)
1575 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1576 else
1577 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1578}
1579
1580static void
1581rpstart(tp)
1582 struct tty *tp;
1583{
1584 struct rp_port *rp;
1585 CHANNEL_t *cp;
1586 struct clist *qp;
1587 int unit, mynor, port, umynor; /* SG */
1588 char flags;
1589 int spl, xmit_fifo_room;
1590 int count, wcount;
1591
1592
1593 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1594 port = (minor(tp->t_dev) & 0x1f); /* SG */
1595 mynor = (port + umynor); /* SG */
1596 unit = minor_to_unit[mynor];
1597 rp = rp_addr(unit) + port;
1598 cp = &rp->rp_channel;
1599 flags = rp->rp_channel.TxControl[3];
1600 spl = spltty();
1601
1602 if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1603 ttwwakeup(tp);
1604 splx(spl);
1605 return;
1606 }
1607 if(rp->rp_xmit_stopped) {
1608 sEnTransmit(cp);
1609 rp->rp_xmit_stopped = 0;
1610 }
1611 count = sGetTxCnt(cp);
1612
1613 if(tp->t_outq.c_cc == 0) {
1614 if((tp->t_state & TS_BUSY) && (count == 0)) {
1615 tp->t_state &= ~TS_BUSY;
1616 }
1617 ttwwakeup(tp);
1618 splx(spl);
1619 return;
1620 }
1621 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1622 qp = &tp->t_outq;
1623 if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1624 tp->t_state |= TS_BUSY;
1625 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1626 wcount = count >> 1;
1627 if ( wcount ) {
1628 rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1629 }
1630 if ( count & 1 ) {
1631 rp_writech1(cp, sGetTxRxDataIO(cp),
1632 ((unsigned char *)(rp->TxBuf))[(count-1)]);
1633 }
1634 }
1635 rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1636
1637 ttwwakeup(tp);
1638 splx(spl);
1639}
1640
1641static
1642void
1643rpstop(tp, flag)
1644 register struct tty *tp;
1645 int flag;
1646{
1647 struct rp_port *rp;
1648 CHANNEL_t *cp;
1649 int unit, mynor, port, umynor; /* SG */
1650 int spl;
1651
1652 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1653 port = (minor(tp->t_dev) & 0x1f); /* SG */
1654 mynor = (port + umynor); /* SG */
1655 unit = minor_to_unit[mynor];
1656 rp = rp_addr(unit) + port;
1657 cp = &rp->rp_channel;
1658
1659 spl = spltty();
1660
1661 if(tp->t_state & TS_BUSY) {
1662 if((tp->t_state&TS_TTSTOP) == 0) {
1663 sFlushTxFIFO(cp);
1664 } else {
1665 if(rp->rp_xmit_stopped == 0) {
1666 sDisTransmit(cp);
1667 rp->rp_xmit_stopped = 1;
1668 }
1669 }
1670 }
1671 splx(spl);
1672 rpstart(tp);
1673}