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