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