FreeBSD/Linux Kernel Cross Reference
sys/dev/rp/rp.c
1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) Comtrol Corporation <support@comtrol.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted prodived that the follwoing conditions
9 * are met.
10 * 1. Redistributions of source code must retain the above copyright
11 * notive, this list of conditions and the following disclainer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials prodided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Comtrol Corporation.
18 * 4. The name of Comtrol Corporation may not be used to endorse or
19 * promote products derived from this software without specific
20 * prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40 * rp.c - for RocketPort FreeBSD
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/endian.h>
46 #include <sys/fcntl.h>
47 #include <sys/malloc.h>
48 #include <sys/serial.h>
49 #include <sys/tty.h>
50 #include <sys/conf.h>
51 #include <sys/kernel.h>
52 #include <machine/resource.h>
53 #include <machine/bus.h>
54 #include <sys/bus.h>
55 #include <sys/rman.h>
56
57 #define ROCKET_C
58 #include <dev/rp/rpreg.h>
59 #include <dev/rp/rpvar.h>
60
61 static const char RocketPortVersion[] = "3.02";
62
63 static Byte_t RData[RDATASIZE] =
64 {
65 0x00, 0x09, 0xf6, 0x82,
66 0x02, 0x09, 0x86, 0xfb,
67 0x04, 0x09, 0x00, 0x0a,
68 0x06, 0x09, 0x01, 0x0a,
69 0x08, 0x09, 0x8a, 0x13,
70 0x0a, 0x09, 0xc5, 0x11,
71 0x0c, 0x09, 0x86, 0x85,
72 0x0e, 0x09, 0x20, 0x0a,
73 0x10, 0x09, 0x21, 0x0a,
74 0x12, 0x09, 0x41, 0xff,
75 0x14, 0x09, 0x82, 0x00,
76 0x16, 0x09, 0x82, 0x7b,
77 0x18, 0x09, 0x8a, 0x7d,
78 0x1a, 0x09, 0x88, 0x81,
79 0x1c, 0x09, 0x86, 0x7a,
80 0x1e, 0x09, 0x84, 0x81,
81 0x20, 0x09, 0x82, 0x7c,
82 0x22, 0x09, 0x0a, 0x0a
83 };
84
85 static Byte_t RRegData[RREGDATASIZE]=
86 {
87 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
88 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
89 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
90 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
91 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
92 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
93 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
94 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
95 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
96 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
97 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
98 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
99 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
100 };
101
102 #if 0
103 /* IRQ number to MUDBAC register 2 mapping */
104 Byte_t sIRQMap[16] =
105 {
106 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
107 };
108 #endif
109
110 Byte_t rp_sBitMapClrTbl[8] =
111 {
112 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
113 };
114
115 Byte_t rp_sBitMapSetTbl[8] =
116 {
117 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
118 };
119
120 static void rpfree(void *);
121
122 /***************************************************************************
123 Function: sReadAiopID
124 Purpose: Read the AIOP idenfication number directly from an AIOP.
125 Call: sReadAiopID(CtlP, aiop)
126 CONTROLLER_T *CtlP; Ptr to controller structure
127 int aiop: AIOP index
128 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
129 is replace by an identifying number.
130 Flag AIOPID_NULL if no valid AIOP is found
131 Warnings: No context switches are allowed while executing this function.
132
133 */
134 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
135 {
136 Byte_t AiopID; /* ID byte from AIOP */
137
138 rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */
139 rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
140 AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
141 if(AiopID == 0x06)
142 return(1);
143 else /* AIOP does not exist */
144 return(-1);
145 }
146
147 /***************************************************************************
148 Function: sReadAiopNumChan
149 Purpose: Read the number of channels available in an AIOP directly from
150 an AIOP.
151 Call: sReadAiopNumChan(CtlP, aiop)
152 CONTROLLER_T *CtlP; Ptr to controller structure
153 int aiop: AIOP index
154 Return: int: The number of channels available
155 Comments: The number of channels is determined by write/reads from identical
156 offsets within the SRAM address spaces for channels 0 and 4.
157 If the channel 4 space is mirrored to channel 0 it is a 4 channel
158 AIOP, otherwise it is an 8 channel.
159 Warnings: No context switches are allowed while executing this function.
160 */
161 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
162 {
163 Word_t x, y;
164
165 rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
166 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */
167 x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
168 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
169 y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
170 if(x != y) /* if different must be 8 chan */
171 return(8);
172 else
173 return(4);
174 }
175
176 /***************************************************************************
177 Function: sInitChan
178 Purpose: Initialization of a channel and channel structure
179 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
180 CONTROLLER_T *CtlP; Ptr to controller structure
181 CHANNEL_T *ChP; Ptr to channel structure
182 int AiopNum; AIOP number within controller
183 int ChanNum; Channel number within AIOP
184 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
185 number exceeds number of channels available in AIOP.
186 Comments: This function must be called before a channel can be used.
187 Warnings: No range checking on any of the parameters is done.
188
189 No context switches are allowed while executing this function.
190 */
191 int sInitChan( CONTROLLER_T *CtlP,
192 CHANNEL_T *ChP,
193 int AiopNum,
194 int ChanNum)
195 {
196 int i, ChOff;
197 Byte_t *ChR;
198 static Byte_t R[4];
199
200 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
201 return(FALSE); /* exceeds num chans in AIOP */
202
203 /* Channel, AIOP, and controller identifiers */
204 ChP->CtlP = CtlP;
205 ChP->ChanID = CtlP->AiopID[AiopNum];
206 ChP->AiopNum = AiopNum;
207 ChP->ChanNum = ChanNum;
208
209 /* Initialize the channel from the RData array */
210 for(i=0; i < RDATASIZE; i+=4)
211 {
212 R[0] = RData[i];
213 R[1] = RData[i+1] + 0x10 * ChanNum;
214 R[2] = RData[i+2];
215 R[3] = RData[i+3];
216 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
217 }
218
219 ChR = ChP->R;
220 for(i=0; i < RREGDATASIZE; i+=4)
221 {
222 ChR[i] = RRegData[i];
223 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
224 ChR[i+2] = RRegData[i+2];
225 ChR[i+3] = RRegData[i+3];
226 }
227
228 /* Indexed registers */
229 ChOff = (Word_t)ChanNum * 0x1000;
230
231 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
232 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
233 ChP->BaudDiv[2] = (Byte_t)BRD9600;
234 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
235 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv));
236
237 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
238 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
239 ChP->TxControl[2] = 0;
240 ChP->TxControl[3] = 0;
241 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
242
243 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
244 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
245 ChP->RxControl[2] = 0;
246 ChP->RxControl[3] = 0;
247 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
248
249 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
250 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
251 ChP->TxEnables[2] = 0;
252 ChP->TxEnables[3] = 0;
253 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables));
254
255 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
256 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
257 ChP->TxCompare[2] = 0;
258 ChP->TxCompare[3] = 0;
259 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare));
260
261 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
262 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
263 ChP->TxReplace1[2] = 0;
264 ChP->TxReplace1[3] = 0;
265 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1));
266
267 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
268 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
269 ChP->TxReplace2[2] = 0;
270 ChP->TxReplace2[3] = 0;
271 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2));
272
273 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
274 ChP->TxFIFO = ChOff + _TX_FIFO;
275
276 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
277 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
278 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
279 rp_writech2(ChP,_INDX_DATA,0);
280 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
281 ChP->RxFIFO = ChOff + _RX_FIFO;
282
283 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
284 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
285 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
286 rp_writech2(ChP,_INDX_DATA,0);
287 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
288 rp_writech2(ChP,_INDX_DATA,0);
289 ChP->TxPrioCnt = ChOff + _TXP_CNT;
290 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
291 rp_writech1(ChP,_INDX_DATA,0);
292 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
293 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
294 rp_writech1(ChP,_INDX_DATA,0);
295 ChP->TxPrioBuf = ChOff + _TXP_BUF;
296 sEnRxProcessor(ChP); /* start the Rx processor */
297
298 return(TRUE);
299 }
300
301 /***************************************************************************
302 Function: sStopRxProcessor
303 Purpose: Stop the receive processor from processing a channel.
304 Call: sStopRxProcessor(ChP)
305 CHANNEL_T *ChP; Ptr to channel structure
306
307 Comments: The receive processor can be started again with sStartRxProcessor().
308 This function causes the receive processor to skip over the
309 stopped channel. It does not stop it from processing other channels.
310
311 Warnings: No context switches are allowed while executing this function.
312
313 Do not leave the receive processor stopped for more than one
314 character time.
315
316 After calling this function a delay of 4 uS is required to ensure
317 that the receive processor is no longer processing this channel.
318 */
319 void sStopRxProcessor(CHANNEL_T *ChP)
320 {
321 Byte_t R[4];
322
323 R[0] = ChP->R[0];
324 R[1] = ChP->R[1];
325 R[2] = 0x0a;
326 R[3] = ChP->R[3];
327 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
328 }
329
330 /***************************************************************************
331 Function: sFlushRxFIFO
332 Purpose: Flush the Rx FIFO
333 Call: sFlushRxFIFO(ChP)
334 CHANNEL_T *ChP; Ptr to channel structure
335 Return: void
336 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
337 while it is being flushed the receive processor is stopped
338 and the transmitter is disabled. After these operations a
339 4 uS delay is done before clearing the pointers to allow
340 the receive processor to stop. These items are handled inside
341 this function.
342 Warnings: No context switches are allowed while executing this function.
343 */
344 void sFlushRxFIFO(CHANNEL_T *ChP)
345 {
346 int i;
347 Byte_t Ch; /* channel number within AIOP */
348 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
349
350 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
351 return; /* don't need to flush */
352
353 RxFIFOEnabled = FALSE;
354 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
355 {
356 RxFIFOEnabled = TRUE;
357 sDisRxFIFO(ChP); /* disable it */
358 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
359 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
360 }
361 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
362 Ch = (Byte_t)sGetChanNum(ChP);
363 rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
364 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */
365 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
366 rp_writech2(ChP,_INDX_DATA,0);
367 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
368 rp_writech2(ChP,_INDX_DATA,0);
369 if(RxFIFOEnabled)
370 sEnRxFIFO(ChP); /* enable Rx FIFO */
371 }
372
373 /***************************************************************************
374 Function: sFlushTxFIFO
375 Purpose: Flush the Tx FIFO
376 Call: sFlushTxFIFO(ChP)
377 CHANNEL_T *ChP; Ptr to channel structure
378 Return: void
379 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
380 while it is being flushed the receive processor is stopped
381 and the transmitter is disabled. After these operations a
382 4 uS delay is done before clearing the pointers to allow
383 the receive processor to stop. These items are handled inside
384 this function.
385 Warnings: No context switches are allowed while executing this function.
386 */
387 void sFlushTxFIFO(CHANNEL_T *ChP)
388 {
389 int i;
390 Byte_t Ch; /* channel number within AIOP */
391 int TxEnabled; /* TRUE if transmitter enabled */
392
393 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
394 return; /* don't need to flush */
395
396 TxEnabled = FALSE;
397 if(ChP->TxControl[3] & TX_ENABLE)
398 {
399 TxEnabled = TRUE;
400 sDisTransmit(ChP); /* disable transmitter */
401 }
402 sStopRxProcessor(ChP); /* stop Rx processor */
403 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
404 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
405 Ch = (Byte_t)sGetChanNum(ChP);
406 rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
407 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */
408 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
409 rp_writech2(ChP,_INDX_DATA,0);
410 if(TxEnabled)
411 sEnTransmit(ChP); /* enable transmitter */
412 sStartRxProcessor(ChP); /* restart Rx processor */
413 }
414
415 /***************************************************************************
416 Function: sWriteTxPrioByte
417 Purpose: Write a byte of priority transmit data to a channel
418 Call: sWriteTxPrioByte(ChP,Data)
419 CHANNEL_T *ChP; Ptr to channel structure
420 Byte_t Data; The transmit data byte
421
422 Return: int: 1 if the bytes is successfully written, otherwise 0.
423
424 Comments: The priority byte is transmitted before any data in the Tx FIFO.
425
426 Warnings: No context switches are allowed while executing this function.
427 */
428 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
429 {
430 Byte_t DWBuf[4]; /* buffer for double word writes */
431
432 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
433 {
434 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
435 if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
436 return(0); /* nothing sent */
437
438 le16enc(DWBuf,ChP->TxPrioBuf); /* data byte address */
439
440 DWBuf[2] = Data; /* data byte value */
441 DWBuf[3] = 0; /* priority buffer pointer */
442 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
443
444 le16enc(DWBuf,ChP->TxPrioCnt); /* Tx priority count address */
445
446 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
447 DWBuf[3] = 0; /* priority buffer pointer */
448 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
449 }
450 else /* write it to Tx FIFO */
451 {
452 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
453 }
454 return(1); /* 1 byte sent */
455 }
456
457 /***************************************************************************
458 Function: sEnInterrupts
459 Purpose: Enable one or more interrupts for a channel
460 Call: sEnInterrupts(ChP,Flags)
461 CHANNEL_T *ChP; Ptr to channel structure
462 Word_t Flags: Interrupt enable flags, can be any combination
463 of the following flags:
464 TXINT_EN: Interrupt on Tx FIFO empty
465 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
466 sSetRxTrigger())
467 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
468 MCINT_EN: Interrupt on modem input change
469 CHANINT_EN: Allow channel interrupt signal to the AIOP's
470 Interrupt Channel Register.
471 Return: void
472 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
473 enabled. If an interrupt enable flag is not set in Flags, that
474 interrupt will not be changed. Interrupts can be disabled with
475 function sDisInterrupts().
476
477 This function sets the appropriate bit for the channel in the AIOP's
478 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
479 this channel's bit to be set in the AIOP's Interrupt Channel Register.
480
481 Interrupts must also be globally enabled before channel interrupts
482 will be passed on to the host. This is done with function
483 sEnGlobalInt().
484
485 In some cases it may be desirable to disable interrupts globally but
486 enable channel interrupts. This would allow the global interrupt
487 status register to be used to determine which AIOPs need service.
488 */
489 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
490 {
491 Byte_t Mask; /* Interrupt Mask Register */
492
493 ChP->RxControl[2] |=
494 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
495
496 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
497
498 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
499
500 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
501
502 if(Flags & CHANINT_EN)
503 {
504 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
505 rp_writech1(ChP,_INT_MASK,Mask);
506 }
507 }
508
509 /***************************************************************************
510 Function: sDisInterrupts
511 Purpose: Disable one or more interrupts for a channel
512 Call: sDisInterrupts(ChP,Flags)
513 CHANNEL_T *ChP; Ptr to channel structure
514 Word_t Flags: Interrupt flags, can be any combination
515 of the following flags:
516 TXINT_EN: Interrupt on Tx FIFO empty
517 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
518 sSetRxTrigger())
519 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
520 MCINT_EN: Interrupt on modem input change
521 CHANINT_EN: Disable channel interrupt signal to the
522 AIOP's Interrupt Channel Register.
523 Return: void
524 Comments: If an interrupt flag is set in Flags, that interrupt will be
525 disabled. If an interrupt flag is not set in Flags, that
526 interrupt will not be changed. Interrupts can be enabled with
527 function sEnInterrupts().
528
529 This function clears the appropriate bit for the channel in the AIOP's
530 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
531 this channel's bit from being set in the AIOP's Interrupt Channel
532 Register.
533 */
534 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
535 {
536 Byte_t Mask; /* Interrupt Mask Register */
537
538 ChP->RxControl[2] &=
539 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
540 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
541 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
542 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
543
544 if(Flags & CHANINT_EN)
545 {
546 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
547 rp_writech1(ChP,_INT_MASK,Mask);
548 }
549 }
550
551 /*********************************************************************
552 Begin FreeBsd-specific driver code
553 **********************************************************************/
554
555 #define POLL_INTERVAL (hz / 100)
556
557 #define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
558 #define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
559 #define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
560
561 /*
562 * The top-level routines begin here
563 */
564
565 static void rpclose(struct tty *tp);
566 static void rphardclose(struct tty *tp);
567 static int rpmodem(struct tty *, int, int);
568 static int rpparam(struct tty *, struct termios *);
569 static void rpstart(struct tty *);
570 static int rpioctl(struct tty *, u_long, caddr_t, struct thread *);
571 static int rpopen(struct tty *);
572
573 static void rp_do_receive(struct rp_port *rp, struct tty *tp,
574 CHANNEL_t *cp, unsigned int ChanStatus)
575 {
576 unsigned int CharNStat;
577 int ToRecv, ch, err = 0;
578
579 ToRecv = sGetRxCnt(cp);
580 if(ToRecv == 0)
581 return;
582
583 /* If status indicates there are errored characters in the
584 FIFO, then enter status mode (a word in FIFO holds
585 characters and status)
586 */
587
588 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
589 if(!(ChanStatus & STATMODE)) {
590 ChanStatus |= STATMODE;
591 sEnRxStatusMode(cp);
592 }
593 }
594 /*
595 if we previously entered status mode then read down the
596 FIFO one word at a time, pulling apart the character and
597 the status. Update error counters depending on status.
598 */
599 tty_lock(tp);
600 if(ChanStatus & STATMODE) {
601 while(ToRecv) {
602 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
603 ch = CharNStat & 0xff;
604
605 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
606 err |= TRE_FRAMING;
607 else if (CharNStat & STMPARITYH)
608 err |= TRE_PARITY;
609 else if (CharNStat & STMRCVROVRH) {
610 rp->rp_overflows++;
611 err |= TRE_OVERRUN;
612 }
613
614 ttydisc_rint(tp, ch, err);
615 ToRecv--;
616 }
617 /*
618 After emtying FIFO in status mode, turn off status mode
619 */
620
621 if(sGetRxCnt(cp) == 0) {
622 sDisRxStatusMode(cp);
623 }
624 } else {
625 ToRecv = sGetRxCnt(cp);
626 while (ToRecv) {
627 ch = rp_readch1(cp,sGetTxRxDataIO(cp));
628 ttydisc_rint(tp, ch & 0xff, err);
629 ToRecv--;
630 }
631 }
632 ttydisc_rint_done(tp);
633 tty_unlock(tp);
634 }
635
636 static void rp_handle_port(struct rp_port *rp)
637 {
638 CHANNEL_t *cp;
639 struct tty *tp;
640 unsigned int IntMask, ChanStatus;
641
642 if(!rp)
643 return;
644
645 cp = &rp->rp_channel;
646 tp = rp->rp_tty;
647 IntMask = sGetChanIntID(cp);
648 IntMask = IntMask & rp->rp_intmask;
649 ChanStatus = sGetChanStatus(cp);
650 if(IntMask & RXF_TRIG)
651 rp_do_receive(rp, tp, cp, ChanStatus);
652 if(IntMask & DELTA_CD) {
653 if(ChanStatus & CD_ACT) {
654 (void)ttydisc_modem(tp, 1);
655 } else {
656 (void)ttydisc_modem(tp, 0);
657 }
658 }
659 /* oldcts = rp->rp_cts;
660 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
661 if(oldcts != rp->rp_cts) {
662 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
663 }
664 */
665 }
666
667 static void rp_do_poll(void *arg)
668 {
669 CONTROLLER_t *ctl;
670 struct rp_port *rp;
671 struct tty *tp;
672 int count;
673 unsigned char CtlMask, AiopMask;
674
675 rp = arg;
676 tp = rp->rp_tty;
677 tty_assert_locked(tp);
678 ctl = rp->rp_ctlp;
679 CtlMask = ctl->ctlmask(ctl);
680 if (CtlMask & (1 << rp->rp_aiop)) {
681 AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop);
682 if (AiopMask & (1 << rp->rp_chan)) {
683 rp_handle_port(rp);
684 }
685 }
686
687 count = sGetTxCnt(&rp->rp_channel);
688 if (count >= 0 && (count <= rp->rp_restart)) {
689 rpstart(tp);
690 }
691 callout_schedule(&rp->rp_timer, POLL_INTERVAL);
692 }
693
694 static struct ttydevsw rp_tty_class = {
695 .tsw_flags = TF_INITLOCK|TF_CALLOUT,
696 .tsw_open = rpopen,
697 .tsw_close = rpclose,
698 .tsw_outwakeup = rpstart,
699 .tsw_ioctl = rpioctl,
700 .tsw_param = rpparam,
701 .tsw_modem = rpmodem,
702 .tsw_free = rpfree,
703 };
704
705
706 static void
707 rpfree(void *softc)
708 {
709 struct rp_port *rp = softc;
710 CONTROLLER_t *ctlp = rp->rp_ctlp;
711
712 atomic_subtract_32(&ctlp->free, 1);
713 }
714
715 int
716 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
717 {
718 int unit;
719 int num_chan;
720 int aiop, chan, port;
721 int ChanStatus;
722 int retval;
723 struct rp_port *rp;
724 struct tty *tp;
725
726 unit = device_get_unit(ctlp->dev);
727
728 printf("RocketPort%d (Version %s) %d ports.\n", unit,
729 RocketPortVersion, num_ports);
730
731 ctlp->num_ports = num_ports;
732 ctlp->rp = rp = (struct rp_port *)
733 malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
734 if (rp == NULL) {
735 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
736 retval = ENOMEM;
737 goto nogo;
738 }
739
740 port = 0;
741 for(aiop=0; aiop < num_aiops; aiop++) {
742 num_chan = sGetAiopNumChan(ctlp, aiop);
743 for(chan=0; chan < num_chan; chan++, port++, rp++) {
744 rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
745 callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
746 rp->rp_port = port;
747 rp->rp_ctlp = ctlp;
748 rp->rp_unit = unit;
749 rp->rp_chan = chan;
750 rp->rp_aiop = aiop;
751
752 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
753 DELTA_CD | DELTA_CTS | DELTA_DSR;
754 #ifdef notdef
755 ChanStatus = sGetChanStatus(&rp->rp_channel);
756 #endif /* notdef */
757 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
758 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
759 unit, aiop, chan);
760 retval = ENXIO;
761 goto nogo;
762 }
763 ChanStatus = sGetChanStatus(&rp->rp_channel);
764 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
765 tty_makedev(tp, NULL, "R%r%r", unit, port);
766 }
767 }
768
769 mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
770 ctlp->hwmtx_init = 1;
771 return (0);
772
773 nogo:
774 rp_releaseresource(ctlp);
775
776 return (retval);
777 }
778
779 void
780 rp_releaseresource(CONTROLLER_t *ctlp)
781 {
782 struct rp_port *rp;
783 int i;
784
785 if (ctlp->rp != NULL) {
786 for (i = 0; i < ctlp->num_ports; i++) {
787 rp = ctlp->rp + i;
788 atomic_add_32(&ctlp->free, 1);
789 tty_lock(rp->rp_tty);
790 tty_rel_gone(rp->rp_tty);
791 }
792 free(ctlp->rp, M_DEVBUF);
793 ctlp->rp = NULL;
794 }
795
796 while (ctlp->free != 0) {
797 pause("rpwt", hz / 10);
798 }
799
800 if (ctlp->hwmtx_init)
801 mtx_destroy(&ctlp->hwmtx);
802 }
803
804 static int
805 rpopen(struct tty *tp)
806 {
807 struct rp_port *rp;
808 int flags;
809 unsigned int IntMask, ChanStatus;
810
811 rp = tty_softc(tp);
812
813 flags = 0;
814 flags |= SET_RTS;
815 flags |= SET_DTR;
816 rp->rp_channel.TxControl[3] =
817 ((rp->rp_channel.TxControl[3]
818 & ~(SET_RTS | SET_DTR)) | flags);
819 rp_writech4(&rp->rp_channel,_INDX_ADDR,
820 le32dec(rp->rp_channel.TxControl));
821 sSetRxTrigger(&rp->rp_channel, TRIG_1);
822 sDisRxStatusMode(&rp->rp_channel);
823 sFlushRxFIFO(&rp->rp_channel);
824 sFlushTxFIFO(&rp->rp_channel);
825
826 sEnInterrupts(&rp->rp_channel,
827 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
828 sSetRxTrigger(&rp->rp_channel, TRIG_1);
829
830 sDisRxStatusMode(&rp->rp_channel);
831 sClrTxXOFF(&rp->rp_channel);
832
833 /* sDisRTSFlowCtl(&rp->rp_channel);
834 sDisCTSFlowCtl(&rp->rp_channel);
835 */
836 sDisTxSoftFlowCtl(&rp->rp_channel);
837
838 sStartRxProcessor(&rp->rp_channel);
839
840 sEnRxFIFO(&rp->rp_channel);
841 sEnTransmit(&rp->rp_channel);
842
843 /* sSetDTR(&rp->rp_channel);
844 sSetRTS(&rp->rp_channel);
845 */
846
847 IntMask = sGetChanIntID(&rp->rp_channel);
848 IntMask = IntMask & rp->rp_intmask;
849 ChanStatus = sGetChanStatus(&rp->rp_channel);
850
851 callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
852
853 device_busy(rp->rp_ctlp->dev);
854 return(0);
855 }
856
857 static void
858 rpclose(struct tty *tp)
859 {
860 struct rp_port *rp;
861
862 rp = tty_softc(tp);
863 callout_stop(&rp->rp_timer);
864 rphardclose(tp);
865 device_unbusy(rp->rp_ctlp->dev);
866 }
867
868 static void
869 rphardclose(struct tty *tp)
870 {
871 struct rp_port *rp;
872 CHANNEL_t *cp;
873
874 rp = tty_softc(tp);
875 cp = &rp->rp_channel;
876
877 sFlushRxFIFO(cp);
878 sFlushTxFIFO(cp);
879 sDisTransmit(cp);
880 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
881 sDisRTSFlowCtl(cp);
882 sDisCTSFlowCtl(cp);
883 sDisTxSoftFlowCtl(cp);
884 sClrTxXOFF(cp);
885
886 #ifdef DJA
887 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
888 sClrDTR(cp);
889 }
890 if(ISCALLOUT(tp->t_dev)) {
891 sClrDTR(cp);
892 }
893 tp->t_actout = FALSE;
894 wakeup(&tp->t_actout);
895 wakeup(TSA_CARR_ON(tp));
896 #endif /* DJA */
897 }
898
899 static int
900 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
901 {
902 struct rp_port *rp;
903
904 rp = tty_softc(tp);
905 switch (cmd) {
906 case TIOCSBRK:
907 sSendBreak(&rp->rp_channel);
908 return (0);
909 case TIOCCBRK:
910 sClrBreak(&rp->rp_channel);
911 return (0);
912 default:
913 return ENOIOCTL;
914 }
915 }
916
917 static int
918 rpmodem(struct tty *tp, int sigon, int sigoff)
919 {
920 struct rp_port *rp;
921 int i, j, k;
922
923 rp = tty_softc(tp);
924 if (sigon != 0 || sigoff != 0) {
925 i = j = 0;
926 if (sigon & SER_DTR)
927 i = SET_DTR;
928 if (sigoff & SER_DTR)
929 j = SET_DTR;
930 if (sigon & SER_RTS)
931 i = SET_RTS;
932 if (sigoff & SER_RTS)
933 j = SET_RTS;
934 rp->rp_channel.TxControl[3] &= ~i;
935 rp->rp_channel.TxControl[3] |= j;
936 rp_writech4(&rp->rp_channel,_INDX_ADDR,
937 le32dec(rp->rp_channel.TxControl));
938 } else {
939 i = sGetChanStatusLo(&rp->rp_channel);
940 j = rp->rp_channel.TxControl[3];
941 k = 0;
942 if (j & SET_DTR)
943 k |= SER_DTR;
944 if (j & SET_RTS)
945 k |= SER_RTS;
946 if (i & CD_ACT)
947 k |= SER_DCD;
948 if (i & DSR_ACT)
949 k |= SER_DSR;
950 if (i & CTS_ACT)
951 k |= SER_CTS;
952 return(k);
953 }
954 return (0);
955 }
956
957 static struct
958 {
959 int baud;
960 int conversion;
961 } baud_table[] = {
962 {B0, 0}, {B50, BRD50}, {B75, BRD75},
963 {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
964 {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
965 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
966 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
967 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
968 {B57600, BRD57600}, {B76800, BRD76800},
969 {B115200, BRD115200}, {B230400, BRD230400},
970 {-1, -1}
971 };
972
973 static int rp_convert_baud(int baud) {
974 int i;
975
976 for (i = 0; baud_table[i].baud >= 0; i++) {
977 if (baud_table[i].baud == baud)
978 break;
979 }
980
981 return baud_table[i].conversion;
982 }
983
984 static int
985 rpparam(tp, t)
986 struct tty *tp;
987 struct termios *t;
988 {
989 struct rp_port *rp;
990 CHANNEL_t *cp;
991 int cflag, iflag, oflag, lflag;
992 int ospeed;
993 #ifdef RPCLOCAL
994 int devshift;
995 #endif
996
997 rp = tty_softc(tp);
998 cp = &rp->rp_channel;
999
1000 cflag = t->c_cflag;
1001 #ifdef RPCLOCAL
1002 devshift = umynor / 32;
1003 devshift = 1 << devshift;
1004 if ( devshift & RPCLOCAL ) {
1005 cflag |= CLOCAL;
1006 }
1007 #endif
1008 iflag = t->c_iflag;
1009 oflag = t->c_oflag;
1010 lflag = t->c_lflag;
1011
1012 ospeed = rp_convert_baud(t->c_ispeed);
1013 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1014 return(EINVAL);
1015
1016 if(t->c_ospeed == 0) {
1017 sClrDTR(cp);
1018 return(0);
1019 }
1020 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1021
1022 /* Set baud rate ----- we only pay attention to ispeed */
1023 sSetDTR(cp);
1024 sSetRTS(cp);
1025 sSetBaud(cp, ospeed);
1026
1027 if(cflag & CSTOPB) {
1028 sSetStop2(cp);
1029 } else {
1030 sSetStop1(cp);
1031 }
1032
1033 if(cflag & PARENB) {
1034 sEnParity(cp);
1035 if(cflag & PARODD) {
1036 sSetOddParity(cp);
1037 } else {
1038 sSetEvenParity(cp);
1039 }
1040 }
1041 else {
1042 sDisParity(cp);
1043 }
1044 if((cflag & CSIZE) == CS8) {
1045 sSetData8(cp);
1046 rp->rp_imask = 0xFF;
1047 } else {
1048 sSetData7(cp);
1049 rp->rp_imask = 0x7F;
1050 }
1051
1052 if(iflag & ISTRIP) {
1053 rp->rp_imask &= 0x7F;
1054 }
1055
1056 if(cflag & CLOCAL) {
1057 rp->rp_intmask &= ~DELTA_CD;
1058 } else {
1059 rp->rp_intmask |= DELTA_CD;
1060 }
1061
1062 /* Put flow control stuff here */
1063
1064 if(cflag & CCTS_OFLOW) {
1065 sEnCTSFlowCtl(cp);
1066 } else {
1067 sDisCTSFlowCtl(cp);
1068 }
1069
1070 if(cflag & CRTS_IFLOW) {
1071 rp->rp_rts_iflow = 1;
1072 } else {
1073 rp->rp_rts_iflow = 0;
1074 }
1075
1076 if(cflag & CRTS_IFLOW) {
1077 sEnRTSFlowCtl(cp);
1078 } else {
1079 sDisRTSFlowCtl(cp);
1080 }
1081
1082 return(0);
1083 }
1084
1085 static void
1086 rpstart(struct tty *tp)
1087 {
1088 struct rp_port *rp;
1089 CHANNEL_t *cp;
1090 char flags;
1091 int xmit_fifo_room;
1092 int i, count, wcount;
1093
1094 rp = tty_softc(tp);
1095 cp = &rp->rp_channel;
1096 flags = rp->rp_channel.TxControl[3];
1097
1098 if(rp->rp_xmit_stopped) {
1099 sEnTransmit(cp);
1100 rp->rp_xmit_stopped = 0;
1101 }
1102
1103 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1104 count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1105 if(xmit_fifo_room > 0) {
1106 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1107 rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1108 }
1109 if ( count & 1 ) {
1110 rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);
1111 }
1112 }
1113 }
Cache object: 6142f1acbecf4861689fa156ca85340c
|