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