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