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 * rp.c - for RocketPort FreeBSD
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/tty.h>
45 #include <sys/proc.h>
46 #include <sys/dkstat.h>
47 #include <sys/conf.h>
48 #include <sys/kernel.h>
49 #include <machine/resource.h>
50 #include <machine/bus.h>
51 #include <sys/bus.h>
52 #include <sys/rman.h>
53
54 #define ROCKET_C
55 #include <dev/rp/rpreg.h>
56 #include <dev/rp/rpvar.h>
57
58 static const char RocketPortVersion[] = "3.02";
59
60 static Byte_t RData[RDATASIZE] =
61 {
62 0x00, 0x09, 0xf6, 0x82,
63 0x02, 0x09, 0x86, 0xfb,
64 0x04, 0x09, 0x00, 0x0a,
65 0x06, 0x09, 0x01, 0x0a,
66 0x08, 0x09, 0x8a, 0x13,
67 0x0a, 0x09, 0xc5, 0x11,
68 0x0c, 0x09, 0x86, 0x85,
69 0x0e, 0x09, 0x20, 0x0a,
70 0x10, 0x09, 0x21, 0x0a,
71 0x12, 0x09, 0x41, 0xff,
72 0x14, 0x09, 0x82, 0x00,
73 0x16, 0x09, 0x82, 0x7b,
74 0x18, 0x09, 0x8a, 0x7d,
75 0x1a, 0x09, 0x88, 0x81,
76 0x1c, 0x09, 0x86, 0x7a,
77 0x1e, 0x09, 0x84, 0x81,
78 0x20, 0x09, 0x82, 0x7c,
79 0x22, 0x09, 0x0a, 0x0a
80 };
81
82 static Byte_t RRegData[RREGDATASIZE]=
83 {
84 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
85 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
86 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
87 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
88 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
89 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
90 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
91 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
92 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
93 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
94 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
95 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
96 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
97 };
98
99 #if 0
100 /* IRQ number to MUDBAC register 2 mapping */
101 Byte_t sIRQMap[16] =
102 {
103 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
104 };
105 #endif
106
107 Byte_t rp_sBitMapClrTbl[8] =
108 {
109 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
110 };
111
112 Byte_t rp_sBitMapSetTbl[8] =
113 {
114 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
115 };
116
117 /* Actually not used */
118 #if notdef
119 struct termios deftermios = {
120 TTYDEF_IFLAG,
121 TTYDEF_OFLAG,
122 TTYDEF_CFLAG,
123 TTYDEF_LFLAG,
124 { CEOF, CEOL, CEOL, CERASE, CWERASE, CKILL, CREPRINT,
125 _POSIX_VDISABLE, CINTR, CQUIT, CSUSP, CDSUSP, CSTART, CSTOP, CLNEXT,
126 CDISCARD, CMIN, CTIME, CSTATUS, _POSIX_VDISABLE },
127 TTYDEF_SPEED,
128 TTYDEF_SPEED
129 };
130 #endif
131
132 /***************************************************************************
133 Function: sReadAiopID
134 Purpose: Read the AIOP idenfication number directly from an AIOP.
135 Call: sReadAiopID(CtlP, aiop)
136 CONTROLLER_T *CtlP; Ptr to controller structure
137 int aiop: AIOP index
138 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
139 is replace by an identifying number.
140 Flag AIOPID_NULL if no valid AIOP is found
141 Warnings: No context switches are allowed while executing this function.
142
143 */
144 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
145 {
146 Byte_t AiopID; /* ID byte from AIOP */
147
148 rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */
149 rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
150 AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
151 if(AiopID == 0x06)
152 return(1);
153 else /* AIOP does not exist */
154 return(-1);
155 }
156
157 /***************************************************************************
158 Function: sReadAiopNumChan
159 Purpose: Read the number of channels available in an AIOP directly from
160 an AIOP.
161 Call: sReadAiopNumChan(CtlP, aiop)
162 CONTROLLER_T *CtlP; Ptr to controller structure
163 int aiop: AIOP index
164 Return: int: The number of channels available
165 Comments: The number of channels is determined by write/reads from identical
166 offsets within the SRAM address spaces for channels 0 and 4.
167 If the channel 4 space is mirrored to channel 0 it is a 4 channel
168 AIOP, otherwise it is an 8 channel.
169 Warnings: No context switches are allowed while executing this function.
170 */
171 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
172 {
173 Word_t x, y;
174
175 rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
176 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */
177 x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
178 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
179 y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
180 if(x != y) /* if different must be 8 chan */
181 return(8);
182 else
183 return(4);
184 }
185
186 /***************************************************************************
187 Function: sInitChan
188 Purpose: Initialization of a channel and channel structure
189 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
190 CONTROLLER_T *CtlP; Ptr to controller structure
191 CHANNEL_T *ChP; Ptr to channel structure
192 int AiopNum; AIOP number within controller
193 int ChanNum; Channel number within AIOP
194 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
195 number exceeds number of channels available in AIOP.
196 Comments: This function must be called before a channel can be used.
197 Warnings: No range checking on any of the parameters is done.
198
199 No context switches are allowed while executing this function.
200 */
201 int sInitChan( CONTROLLER_T *CtlP,
202 CHANNEL_T *ChP,
203 int AiopNum,
204 int ChanNum)
205 {
206 int i, ChOff;
207 Byte_t *ChR;
208 static Byte_t R[4];
209
210 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
211 return(FALSE); /* exceeds num chans in AIOP */
212
213 /* Channel, AIOP, and controller identifiers */
214 ChP->CtlP = CtlP;
215 ChP->ChanID = CtlP->AiopID[AiopNum];
216 ChP->AiopNum = AiopNum;
217 ChP->ChanNum = ChanNum;
218
219 /* Initialize the channel from the RData array */
220 for(i=0; i < RDATASIZE; i+=4)
221 {
222 R[0] = RData[i];
223 R[1] = RData[i+1] + 0x10 * ChanNum;
224 R[2] = RData[i+2];
225 R[3] = RData[i+3];
226 rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)&R[0]));
227 }
228
229 ChR = ChP->R;
230 for(i=0; i < RREGDATASIZE; i+=4)
231 {
232 ChR[i] = RRegData[i];
233 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
234 ChR[i+2] = RRegData[i+2];
235 ChR[i+3] = RRegData[i+3];
236 }
237
238 /* Indexed registers */
239 ChOff = (Word_t)ChanNum * 0x1000;
240
241 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
242 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
243 ChP->BaudDiv[2] = (Byte_t)BRD9600;
244 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
245 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->BaudDiv[0]);
246
247 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
248 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
249 ChP->TxControl[2] = 0;
250 ChP->TxControl[3] = 0;
251 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
252
253 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
254 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
255 ChP->RxControl[2] = 0;
256 ChP->RxControl[3] = 0;
257 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
258
259 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
260 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
261 ChP->TxEnables[2] = 0;
262 ChP->TxEnables[3] = 0;
263 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxEnables[0]);
264
265 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
266 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
267 ChP->TxCompare[2] = 0;
268 ChP->TxCompare[3] = 0;
269 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxCompare[0]);
270
271 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
272 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
273 ChP->TxReplace1[2] = 0;
274 ChP->TxReplace1[3] = 0;
275 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace1[0]);
276
277 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
278 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
279 ChP->TxReplace2[2] = 0;
280 ChP->TxReplace2[3] = 0;
281 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace2[0]);
282
283 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
284 ChP->TxFIFO = ChOff + _TX_FIFO;
285
286 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
287 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
288 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
289 rp_writech2(ChP,_INDX_DATA,0);
290 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
291 ChP->RxFIFO = ChOff + _RX_FIFO;
292
293 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
294 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
295 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
296 rp_writech2(ChP,_INDX_DATA,0);
297 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
298 rp_writech2(ChP,_INDX_DATA,0);
299 ChP->TxPrioCnt = ChOff + _TXP_CNT;
300 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
301 rp_writech1(ChP,_INDX_DATA,0);
302 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
303 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
304 rp_writech1(ChP,_INDX_DATA,0);
305 ChP->TxPrioBuf = ChOff + _TXP_BUF;
306 sEnRxProcessor(ChP); /* start the Rx processor */
307
308 return(TRUE);
309 }
310
311 /***************************************************************************
312 Function: sStopRxProcessor
313 Purpose: Stop the receive processor from processing a channel.
314 Call: sStopRxProcessor(ChP)
315 CHANNEL_T *ChP; Ptr to channel structure
316
317 Comments: The receive processor can be started again with sStartRxProcessor().
318 This function causes the receive processor to skip over the
319 stopped channel. It does not stop it from processing other channels.
320
321 Warnings: No context switches are allowed while executing this function.
322
323 Do not leave the receive processor stopped for more than one
324 character time.
325
326 After calling this function a delay of 4 uS is required to ensure
327 that the receive processor is no longer processing this channel.
328 */
329 void sStopRxProcessor(CHANNEL_T *ChP)
330 {
331 Byte_t R[4];
332
333 R[0] = ChP->R[0];
334 R[1] = ChP->R[1];
335 R[2] = 0x0a;
336 R[3] = ChP->R[3];
337 rp_writech4(ChP, _INDX_ADDR,*(DWord_t *)&R[0]);
338 }
339
340 /***************************************************************************
341 Function: sFlushRxFIFO
342 Purpose: Flush the Rx FIFO
343 Call: sFlushRxFIFO(ChP)
344 CHANNEL_T *ChP; Ptr to channel structure
345 Return: void
346 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
347 while it is being flushed the receive processor is stopped
348 and the transmitter is disabled. After these operations a
349 4 uS delay is done before clearing the pointers to allow
350 the receive processor to stop. These items are handled inside
351 this function.
352 Warnings: No context switches are allowed while executing this function.
353 */
354 void sFlushRxFIFO(CHANNEL_T *ChP)
355 {
356 int i;
357 Byte_t Ch; /* channel number within AIOP */
358 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
359
360 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
361 return; /* don't need to flush */
362
363 RxFIFOEnabled = FALSE;
364 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
365 {
366 RxFIFOEnabled = TRUE;
367 sDisRxFIFO(ChP); /* disable it */
368 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
369 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
370 }
371 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
372 Ch = (Byte_t)sGetChanNum(ChP);
373 rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
374 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */
375 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
376 rp_writech2(ChP,_INDX_DATA,0);
377 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
378 rp_writech2(ChP,_INDX_DATA,0);
379 if(RxFIFOEnabled)
380 sEnRxFIFO(ChP); /* enable Rx FIFO */
381 }
382
383 /***************************************************************************
384 Function: sFlushTxFIFO
385 Purpose: Flush the Tx FIFO
386 Call: sFlushTxFIFO(ChP)
387 CHANNEL_T *ChP; Ptr to channel structure
388 Return: void
389 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
390 while it is being flushed the receive processor is stopped
391 and the transmitter is disabled. After these operations a
392 4 uS delay is done before clearing the pointers to allow
393 the receive processor to stop. These items are handled inside
394 this function.
395 Warnings: No context switches are allowed while executing this function.
396 */
397 void sFlushTxFIFO(CHANNEL_T *ChP)
398 {
399 int i;
400 Byte_t Ch; /* channel number within AIOP */
401 int TxEnabled; /* TRUE if transmitter enabled */
402
403 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
404 return; /* don't need to flush */
405
406 TxEnabled = FALSE;
407 if(ChP->TxControl[3] & TX_ENABLE)
408 {
409 TxEnabled = TRUE;
410 sDisTransmit(ChP); /* disable transmitter */
411 }
412 sStopRxProcessor(ChP); /* stop Rx processor */
413 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
414 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
415 Ch = (Byte_t)sGetChanNum(ChP);
416 rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
417 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */
418 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
419 rp_writech2(ChP,_INDX_DATA,0);
420 if(TxEnabled)
421 sEnTransmit(ChP); /* enable transmitter */
422 sStartRxProcessor(ChP); /* restart Rx processor */
423 }
424
425 /***************************************************************************
426 Function: sWriteTxPrioByte
427 Purpose: Write a byte of priority transmit data to a channel
428 Call: sWriteTxPrioByte(ChP,Data)
429 CHANNEL_T *ChP; Ptr to channel structure
430 Byte_t Data; The transmit data byte
431
432 Return: int: 1 if the bytes is successfully written, otherwise 0.
433
434 Comments: The priority byte is transmitted before any data in the Tx FIFO.
435
436 Warnings: No context switches are allowed while executing this function.
437 */
438 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
439 {
440 Byte_t DWBuf[4]; /* buffer for double word writes */
441 Word_t *WordPtr; /* must be far because Win SS != DS */
442
443 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
444 {
445 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
446 if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
447 return(0); /* nothing sent */
448
449 WordPtr = (Word_t *)(&DWBuf[0]);
450 *WordPtr = ChP->TxPrioBuf; /* data byte address */
451
452 DWBuf[2] = Data; /* data byte value */
453 rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
454
455 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
456
457 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
458 DWBuf[3] = 0; /* priority buffer pointer */
459 rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
460 }
461 else /* write it to Tx FIFO */
462 {
463 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
464 }
465 return(1); /* 1 byte sent */
466 }
467
468 /***************************************************************************
469 Function: sEnInterrupts
470 Purpose: Enable one or more interrupts for a channel
471 Call: sEnInterrupts(ChP,Flags)
472 CHANNEL_T *ChP; Ptr to channel structure
473 Word_t Flags: Interrupt enable flags, can be any combination
474 of the following flags:
475 TXINT_EN: Interrupt on Tx FIFO empty
476 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
477 sSetRxTrigger())
478 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
479 MCINT_EN: Interrupt on modem input change
480 CHANINT_EN: Allow channel interrupt signal to the AIOP's
481 Interrupt Channel Register.
482 Return: void
483 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
484 enabled. If an interrupt enable flag is not set in Flags, that
485 interrupt will not be changed. Interrupts can be disabled with
486 function sDisInterrupts().
487
488 This function sets the appropriate bit for the channel in the AIOP's
489 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
490 this channel's bit to be set in the AIOP's Interrupt Channel Register.
491
492 Interrupts must also be globally enabled before channel interrupts
493 will be passed on to the host. This is done with function
494 sEnGlobalInt().
495
496 In some cases it may be desirable to disable interrupts globally but
497 enable channel interrupts. This would allow the global interrupt
498 status register to be used to determine which AIOPs need service.
499 */
500 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
501 {
502 Byte_t Mask; /* Interrupt Mask Register */
503
504 ChP->RxControl[2] |=
505 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
506
507 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
508
509 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
510
511 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
512
513 if(Flags & CHANINT_EN)
514 {
515 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
516 rp_writech1(ChP,_INT_MASK,Mask);
517 }
518 }
519
520 /***************************************************************************
521 Function: sDisInterrupts
522 Purpose: Disable one or more interrupts for a channel
523 Call: sDisInterrupts(ChP,Flags)
524 CHANNEL_T *ChP; Ptr to channel structure
525 Word_t Flags: Interrupt flags, can be any combination
526 of the following flags:
527 TXINT_EN: Interrupt on Tx FIFO empty
528 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
529 sSetRxTrigger())
530 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
531 MCINT_EN: Interrupt on modem input change
532 CHANINT_EN: Disable channel interrupt signal to the
533 AIOP's Interrupt Channel Register.
534 Return: void
535 Comments: If an interrupt flag is set in Flags, that interrupt will be
536 disabled. If an interrupt flag is not set in Flags, that
537 interrupt will not be changed. Interrupts can be enabled with
538 function sEnInterrupts().
539
540 This function clears the appropriate bit for the channel in the AIOP's
541 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
542 this channel's bit from being set in the AIOP's Interrupt Channel
543 Register.
544 */
545 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
546 {
547 Byte_t Mask; /* Interrupt Mask Register */
548
549 ChP->RxControl[2] &=
550 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
551 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
552 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
553 rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
554
555 if(Flags & CHANINT_EN)
556 {
557 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
558 rp_writech1(ChP,_INT_MASK,Mask);
559 }
560 }
561
562 /*********************************************************************
563 Begin FreeBsd-specific driver code
564 **********************************************************************/
565
566 static timeout_t rpdtrwakeup;
567
568 static d_open_t rpopen;
569 static d_close_t rpclose;
570 static d_write_t rpwrite;
571 static d_ioctl_t rpioctl;
572
573 #define CDEV_MAJOR 81
574 struct cdevsw rp_cdevsw = {
575 /* open */ rpopen,
576 /* close */ rpclose,
577 /* read */ ttyread,
578 /* write */ rpwrite,
579 /* ioctl */ rpioctl,
580 /* poll */ ttypoll,
581 /* mmap */ nommap,
582 /* strategy */ nostrategy,
583 /* name */ "rp",
584 /* maj */ CDEV_MAJOR,
585 /* dump */ nodump,
586 /* psize */ nopsize,
587 /* flags */ D_TTY,
588 };
589
590 static int rp_num_ports_open = 0;
591 static int rp_ndevs = 0;
592 static int minor_to_unit[128];
593
594 static int rp_num_ports[4]; /* Number of ports on each controller */
595
596 #define _INLINE_ __inline
597 #define POLL_INTERVAL 1
598
599 #define CALLOUT_MASK 0x80
600 #define CONTROL_MASK 0x60
601 #define CONTROL_INIT_STATE 0x20
602 #define CONTROL_LOCK_STATE 0x40
603 #define DEV_UNIT(dev) (MINOR_TO_UNIT(minor(dev))
604 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
605 #define MINOR_MAGIC(dev) ((minor(dev)) & ~MINOR_MAGIC_MASK)
606 #define IS_CALLOUT(dev) (minor(dev) & CALLOUT_MASK)
607 #define IS_CONTROL(dev) (minor(dev) & CONTROL_MASK)
608
609 #define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
610 #define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
611 #define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
612
613 static struct rp_port *p_rp_addr[4];
614 static struct rp_port *p_rp_table[MAX_RP_PORTS];
615 #define rp_addr(unit) (p_rp_addr[unit])
616 #define rp_table(port) (p_rp_table[port])
617
618 /*
619 * The top-level routines begin here
620 */
621
622 static int rpparam __P((struct tty *, struct termios *));
623 static void rpstart __P((struct tty *));
624 static void rpstop __P((struct tty *, int));
625 static void rphardclose __P((struct rp_port *));
626 static void rp_disc_optim __P((struct tty *tp, struct termios *t));
627
628 static _INLINE_ void rp_do_receive(struct rp_port *rp, struct tty *tp,
629 CHANNEL_t *cp, unsigned int ChanStatus)
630 {
631 int spl;
632 unsigned int CharNStat;
633 int ToRecv, wRecv, ch, ttynocopy;
634
635 ToRecv = sGetRxCnt(cp);
636 if(ToRecv == 0)
637 return;
638
639 /* If status indicates there are errored characters in the
640 FIFO, then enter status mode (a word in FIFO holds
641 characters and status)
642 */
643
644 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
645 if(!(ChanStatus & STATMODE)) {
646 ChanStatus |= STATMODE;
647 sEnRxStatusMode(cp);
648 }
649 }
650 /*
651 if we previously entered status mode then read down the
652 FIFO one word at a time, pulling apart the character and
653 the status. Update error counters depending on status.
654 */
655 if(ChanStatus & STATMODE) {
656 while(ToRecv) {
657 if(tp->t_state & TS_TBLOCK) {
658 break;
659 }
660 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
661 ch = CharNStat & 0xff;
662
663 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
664 ch |= TTY_FE;
665 else if (CharNStat & STMPARITYH)
666 ch |= TTY_PE;
667 else if (CharNStat & STMRCVROVRH)
668 rp->rp_overflows++;
669
670 (*linesw[tp->t_line].l_rint)(ch, tp);
671 ToRecv--;
672 }
673 /*
674 After emtying FIFO in status mode, turn off status mode
675 */
676
677 if(sGetRxCnt(cp) == 0) {
678 sDisRxStatusMode(cp);
679 }
680 } else {
681 /*
682 * Avoid the grotesquely inefficient lineswitch routine
683 * (ttyinput) in "raw" mode. It usually takes about 450
684 * instructions (that's without canonical processing or echo!).
685 * slinput is reasonably fast (usually 40 instructions plus
686 * call overhead).
687 */
688 ToRecv = sGetRxCnt(cp);
689 if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
690 if ( ToRecv > RXFIFO_SIZE ) {
691 ToRecv = RXFIFO_SIZE;
692 }
693 wRecv = ToRecv >> 1;
694 if ( wRecv ) {
695 rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
696 }
697 if ( ToRecv & 1 ) {
698 ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
699 }
700 tk_nin += ToRecv;
701 tk_rawcc += ToRecv;
702 tp->t_rawcc += ToRecv;
703 ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
704 ttwakeup(tp);
705 } else {
706 while (ToRecv) {
707 if(tp->t_state & TS_TBLOCK) {
708 break;
709 }
710 ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
711 spl = spltty();
712 (*linesw[tp->t_line].l_rint)(ch, tp);
713 splx(spl);
714 ToRecv--;
715 }
716 }
717 }
718 }
719
720 static _INLINE_ void rp_handle_port(struct rp_port *rp)
721 {
722 CHANNEL_t *cp;
723 struct tty *tp;
724 unsigned int IntMask, ChanStatus;
725
726 if(!rp)
727 return;
728
729 cp = &rp->rp_channel;
730 tp = rp->rp_tty;
731 IntMask = sGetChanIntID(cp);
732 IntMask = IntMask & rp->rp_intmask;
733 ChanStatus = sGetChanStatus(cp);
734 if(IntMask & RXF_TRIG)
735 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
736 rp_do_receive(rp, tp, cp, ChanStatus);
737 }
738 if(IntMask & DELTA_CD) {
739 if(ChanStatus & CD_ACT) {
740 if(!(tp->t_state & TS_CARR_ON) ) {
741 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
742 }
743 } else {
744 if((tp->t_state & TS_CARR_ON)) {
745 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
746 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
747 rphardclose(rp);
748 }
749 }
750 }
751 }
752 /* oldcts = rp->rp_cts;
753 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
754 if(oldcts != rp->rp_cts) {
755 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
756 }
757 */
758 }
759
760 static void rp_do_poll(void *not_used)
761 {
762 CONTROLLER_t *ctl;
763 struct rp_port *rp;
764 struct tty *tp;
765 int unit, aiop, ch, line, count;
766 unsigned char CtlMask, AiopMask;
767
768 for(unit = 0; unit < rp_ndevs; unit++) {
769 rp = rp_addr(unit);
770 ctl = rp->rp_ctlp;
771 CtlMask = ctl->ctlmask(ctl);
772 for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
773 if(CtlMask & 1) {
774 AiopMask = sGetAiopIntStatus(ctl, aiop);
775 for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
776 if(AiopMask & 1) {
777 line = (unit << 5) | (aiop << 3) | ch;
778 rp = rp_table(line);
779 rp_handle_port(rp);
780 }
781 }
782 }
783 }
784
785 for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
786 line++, rp++) {
787 tp = rp->rp_tty;
788 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
789 count = sGetTxCnt(&rp->rp_channel);
790 if(count == 0)
791 tp->t_state &= ~(TS_BUSY);
792 if(!(tp->t_state & TS_TTSTOP) &&
793 (count <= rp->rp_restart)) {
794 (*linesw[tp->t_line].l_start)(tp);
795 }
796 }
797 }
798 }
799 if(rp_num_ports_open)
800 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
801 }
802
803 int
804 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
805 {
806 int oldspl, unit;
807 int num_chan;
808 int aiop, chan, port;
809 int ChanStatus, line, i, count;
810 int retval;
811 struct rp_port *rp;
812 struct tty *tty;
813 dev_t *dev_nodes;
814
815 unit = device_get_unit(ctlp->dev);
816
817 printf("RocketPort%d (Version %s) %d ports.\n", unit,
818 RocketPortVersion, num_ports);
819 rp_num_ports[unit] = num_ports;
820
821 ctlp->rp = rp = (struct rp_port *)
822 malloc(sizeof(struct rp_port) * num_ports, M_TTYS, M_NOWAIT);
823 if (rp == NULL) {
824 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
825 retval = ENOMEM;
826 goto nogo;
827 }
828
829 count = unit * 32; /* board times max ports per card SG */
830 for(i=count;i < (count + rp_num_ports[unit]);i++)
831 minor_to_unit[i] = unit;
832
833 bzero(rp, sizeof(struct rp_port) * num_ports);
834 ctlp->tty = tty = (struct tty *)
835 malloc(sizeof(struct tty) * num_ports, M_TTYS,
836 M_NOWAIT | M_ZERO);
837 if(tty == NULL) {
838 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc tty structures.\n");
839 retval = ENOMEM;
840 goto nogo;
841 }
842
843 oldspl = spltty();
844 rp_addr(unit) = rp;
845 splx(oldspl);
846
847 dev_nodes = ctlp->dev_nodes = malloc(sizeof(*(ctlp->dev_nodes)) * rp_num_ports[unit] * 6, M_DEVBUF, M_NOWAIT | M_ZERO);
848 if(ctlp->dev_nodes == NULL) {
849 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc device node structures.\n");
850 retval = ENOMEM;
851 goto nogo;
852 }
853
854 for (i = 0 ; i < rp_num_ports[unit] ; i++) {
855 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i,
856 UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
857 i <= 9 ? '' + i : 'a' + i - 10);
858 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x20,
859 UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
860 i <= 9 ? '' + i : 'a' + i - 10);
861 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x40,
862 UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
863 i <= 9 ? '' + i : 'a' + i - 10);
864 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x80,
865 UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
866 i <= 9 ? '' + i : 'a' + i - 10);
867 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xa0,
868 UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
869 i <= 9 ? '' + i : 'a' + i - 10);
870 *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xc0,
871 UID_ROOT, GID_WHEEL, 0666, "cualR%c",
872 i <= 9 ? '' + i : 'a' + i - 10);
873 }
874
875 port = 0;
876 for(aiop=0; aiop < num_aiops; aiop++) {
877 num_chan = sGetAiopNumChan(ctlp, aiop);
878 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
879 rp->rp_tty = tty;
880 rp->rp_port = port;
881 rp->rp_ctlp = ctlp;
882 rp->rp_unit = unit;
883 rp->rp_chan = chan;
884 rp->rp_aiop = aiop;
885
886 tty->t_line = 0;
887 /* tty->t_termios = deftermios;
888 */
889 rp->dtr_wait = 3 * hz;
890 rp->it_in.c_iflag = 0;
891 rp->it_in.c_oflag = 0;
892 rp->it_in.c_cflag = TTYDEF_CFLAG;
893 rp->it_in.c_lflag = 0;
894 termioschars(&rp->it_in);
895 /* termioschars(&tty->t_termios);
896 */
897 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
898 rp->it_out = rp->it_in;
899
900 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
901 DELTA_CD | DELTA_CTS | DELTA_DSR;
902 #if notdef
903 ChanStatus = sGetChanStatus(&rp->rp_channel);
904 #endif /* notdef */
905 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
906 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
907 unit, aiop, chan);
908 retval = ENXIO;
909 goto nogo;
910 }
911 ChanStatus = sGetChanStatus(&rp->rp_channel);
912 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
913 line = (unit << 5) | (aiop << 3) | chan;
914 rp_table(line) = rp;
915 }
916 }
917
918 rp_ndevs++;
919 return (0);
920
921 nogo:
922 rp_releaseresource(ctlp);
923
924 return (retval);
925 }
926
927 void
928 rp_releaseresource(CONTROLLER_t *ctlp)
929 {
930 int i, s, unit;
931
932 unit = device_get_unit(ctlp->dev);
933
934 if (ctlp->rp != NULL) {
935 s = spltty();
936 for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
937 if (p_rp_addr[i] == ctlp->rp)
938 p_rp_addr[i] = NULL;
939 for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
940 if (p_rp_table[i] == ctlp->rp)
941 p_rp_table[i] = NULL;
942 splx(s);
943 free(ctlp->rp, M_DEVBUF);
944 ctlp->rp = NULL;
945 }
946 if (ctlp->tty != NULL) {
947 free(ctlp->tty, M_DEVBUF);
948 ctlp->tty = NULL;
949 }
950 if (ctlp->dev != NULL) {
951 for (i = 0 ; i < rp_num_ports[unit] * 6 ; i++)
952 destroy_dev(ctlp->dev_nodes[i]);
953 free(ctlp->dev_nodes, M_DEVBUF);
954 ctlp->dev = NULL;
955 }
956 }
957
958 int
959 rpopen(dev, flag, mode, p)
960 dev_t dev;
961 int flag, mode;
962 struct proc *p;
963 {
964 struct rp_port *rp;
965 int unit, port, mynor, umynor, flags; /* SG */
966 struct tty *tp;
967 int oldspl, error;
968 unsigned int IntMask, ChanStatus;
969
970
971 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
972 port = (minor(dev) & 0x1f); /* SG */
973 mynor = (port + umynor); /* SG */
974 unit = minor_to_unit[mynor];
975 if (rp_addr(unit) == NULL)
976 return (ENXIO);
977 if(IS_CONTROL(dev))
978 return(0);
979 rp = rp_addr(unit) + port;
980 /* rp->rp_tty = &rp_tty[rp->rp_port];
981 */
982 tp = rp->rp_tty;
983 dev->si_tty = tp;
984
985 oldspl = spltty();
986
987 open_top:
988 while(rp->state & ~SET_DTR) {
989 error = tsleep(&rp->dtr_wait, TTIPRI | PCATCH, "rpdtr", 0);
990 if(error != 0)
991 goto out;
992 }
993
994 if(tp->t_state & TS_ISOPEN) {
995 if(IS_CALLOUT(dev)) {
996 if(!rp->active_out) {
997 error = EBUSY;
998 goto out;
999 }
1000 } else {
1001 if(rp->active_out) {
1002 if(flag & O_NONBLOCK) {
1003 error = EBUSY;
1004 goto out;
1005 }
1006 error = tsleep(&rp->active_out,
1007 TTIPRI | PCATCH, "rpbi", 0);
1008 if(error != 0)
1009 goto out;
1010 goto open_top;
1011 }
1012 }
1013 if(tp->t_state & TS_XCLUDE && suser(p) != 0) {
1014 splx(oldspl);
1015 error = EBUSY;
1016 goto out2;
1017 }
1018 }
1019 else {
1020 tp->t_dev = dev;
1021 tp->t_param = rpparam;
1022 tp->t_oproc = rpstart;
1023 tp->t_stop = rpstop;
1024 tp->t_line = 0;
1025 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1026 tp->t_ififosize = 512;
1027 tp->t_ispeedwat = (speed_t)-1;
1028 tp->t_ospeedwat = (speed_t)-1;
1029 flags = 0;
1030 flags |= SET_RTS;
1031 flags |= SET_DTR;
1032 rp->rp_channel.TxControl[3] =
1033 ((rp->rp_channel.TxControl[3]
1034 & ~(SET_RTS | SET_DTR)) | flags);
1035 rp_writech4(&rp->rp_channel,_INDX_ADDR,
1036 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1037 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1038 sDisRxStatusMode(&rp->rp_channel);
1039 sFlushRxFIFO(&rp->rp_channel);
1040 sFlushTxFIFO(&rp->rp_channel);
1041
1042 sEnInterrupts(&rp->rp_channel,
1043 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1044 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1045
1046 sDisRxStatusMode(&rp->rp_channel);
1047 sClrTxXOFF(&rp->rp_channel);
1048
1049 /* sDisRTSFlowCtl(&rp->rp_channel);
1050 sDisCTSFlowCtl(&rp->rp_channel);
1051 */
1052 sDisTxSoftFlowCtl(&rp->rp_channel);
1053
1054 sStartRxProcessor(&rp->rp_channel);
1055
1056 sEnRxFIFO(&rp->rp_channel);
1057 sEnTransmit(&rp->rp_channel);
1058
1059 /* sSetDTR(&rp->rp_channel);
1060 sSetRTS(&rp->rp_channel);
1061 */
1062
1063 ++rp->wopeners;
1064 error = rpparam(tp, &tp->t_termios);
1065 --rp->wopeners;
1066 if(error != 0) {
1067 splx(oldspl);
1068 return(error);
1069 }
1070
1071 rp_num_ports_open++;
1072
1073 IntMask = sGetChanIntID(&rp->rp_channel);
1074 IntMask = IntMask & rp->rp_intmask;
1075 ChanStatus = sGetChanStatus(&rp->rp_channel);
1076 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1077 if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1078 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1079 }
1080 }
1081
1082 if(rp_num_ports_open == 1)
1083 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
1084
1085 }
1086
1087 if(!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1088 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1089 ++rp->wopeners;
1090 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH,
1091 "rpdcd", 0);
1092 --rp->wopeners;
1093 if(error != 0)
1094 goto out;
1095 goto open_top;
1096 }
1097 error = (*linesw[tp->t_line].l_open)(dev, tp);
1098
1099 rp_disc_optim(tp, &tp->t_termios);
1100 if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1101 rp->active_out = TRUE;
1102
1103 /* if(rp_num_ports_open == 1)
1104 timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
1105 */
1106 out:
1107 splx(oldspl);
1108 if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1109 rphardclose(rp);
1110 }
1111 out2:
1112 if (error == 0)
1113 device_busy(rp->rp_ctlp->dev);
1114 return(error);
1115 }
1116
1117 int
1118 rpclose(dev, flag, mode, p)
1119 dev_t dev;
1120 int flag, mode;
1121 struct proc *p;
1122 {
1123 int oldspl, unit, mynor, umynor, port; /* SG */
1124 struct rp_port *rp;
1125 struct tty *tp;
1126 CHANNEL_t *cp;
1127
1128 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1129 port = (minor(dev) & 0x1f); /* SG */
1130 mynor = (port + umynor); /* SG */
1131 unit = minor_to_unit[mynor]; /* SG */
1132
1133 if(IS_CONTROL(dev))
1134 return(0);
1135 rp = rp_addr(unit) + port;
1136 cp = &rp->rp_channel;
1137 tp = rp->rp_tty;
1138
1139 oldspl = spltty();
1140 (*linesw[tp->t_line].l_close)(tp, flag);
1141 rp_disc_optim(tp, &tp->t_termios);
1142 rpstop(tp, FREAD | FWRITE);
1143 rphardclose(rp);
1144
1145 tp->t_state &= ~TS_BUSY;
1146 ttyclose(tp);
1147
1148 splx(oldspl);
1149
1150 device_unbusy(rp->rp_ctlp->dev);
1151
1152 return(0);
1153 }
1154
1155 static void
1156 rphardclose(struct rp_port *rp)
1157 {
1158 int mynor;
1159 struct tty *tp;
1160 CHANNEL_t *cp;
1161
1162 cp = &rp->rp_channel;
1163 tp = rp->rp_tty;
1164 mynor = MINOR_MAGIC(tp->t_dev);
1165
1166 sFlushRxFIFO(cp);
1167 sFlushTxFIFO(cp);
1168 sDisTransmit(cp);
1169 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1170 sDisRTSFlowCtl(cp);
1171 sDisCTSFlowCtl(cp);
1172 sDisTxSoftFlowCtl(cp);
1173 sClrTxXOFF(cp);
1174
1175 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1176 sClrDTR(cp);
1177 }
1178 if(IS_CALLOUT(tp->t_dev)) {
1179 sClrDTR(cp);
1180 }
1181 if(rp->dtr_wait != 0) {
1182 timeout(rpdtrwakeup, rp, rp->dtr_wait);
1183 rp->state |= ~SET_DTR;
1184 }
1185
1186 rp->active_out = FALSE;
1187 wakeup(&rp->active_out);
1188 wakeup(TSA_CARR_ON(tp));
1189 }
1190
1191 static
1192 int
1193 rpwrite(dev, uio, flag)
1194 dev_t dev;
1195 struct uio *uio;
1196 int flag;
1197 {
1198 struct rp_port *rp;
1199 struct tty *tp;
1200 int unit, mynor, port, umynor, error = 0; /* SG */
1201
1202 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1203 port = (minor(dev) & 0x1f); /* SG */
1204 mynor = (port + umynor); /* SG */
1205 unit = minor_to_unit[mynor]; /* SG */
1206
1207 if(IS_CONTROL(dev))
1208 return(ENODEV);
1209 rp = rp_addr(unit) + port;
1210 tp = rp->rp_tty;
1211 while(rp->rp_disable_writes) {
1212 rp->rp_waiting = 1;
1213 error = ttysleep(tp, (caddr_t)rp, TTOPRI|PCATCH, "rp_write", 0);
1214 if (error)
1215 return(error);
1216 }
1217
1218 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1219 return error;
1220 }
1221
1222 static void
1223 rpdtrwakeup(void *chan)
1224 {
1225 struct rp_port *rp;
1226
1227 rp = (struct rp_port *)chan;
1228 rp->state &= SET_DTR;
1229 wakeup(&rp->dtr_wait);
1230 }
1231
1232 int
1233 rpioctl(dev, cmd, data, flag, p)
1234 dev_t dev;
1235 u_long cmd;
1236 caddr_t data;
1237 int flag;
1238 struct proc *p;
1239 {
1240 struct rp_port *rp;
1241 CHANNEL_t *cp;
1242 struct tty *tp;
1243 int unit, mynor, port, umynor; /* SG */
1244 int oldspl;
1245 int error = 0;
1246 int arg, flags, result, ChanStatus;
1247 struct termios *t;
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(p);
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, p);
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(p);
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: 4ce1cede1c18a38e8186100e162eba5d
|