2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) Comtrol Corporation <support@comtrol.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted prodived that the follwoing conditions
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.
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
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * rp.c - for RocketPort FreeBSD
43 #include "opt_compat.h"
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/endian.h>
48 #include <sys/fcntl.h>
49 #include <sys/malloc.h>
50 #include <sys/serial.h>
53 #include <sys/kernel.h>
54 #include <machine/resource.h>
55 #include <machine/bus.h>
60 #include <dev/rp/rpreg.h>
61 #include <dev/rp/rpvar.h>
63 static const char RocketPortVersion[] = "3.02";
65 static Byte_t RData[RDATASIZE] =
67 0x00, 0x09, 0xf6, 0x82,
68 0x02, 0x09, 0x86, 0xfb,
69 0x04, 0x09, 0x00, 0x0a,
70 0x06, 0x09, 0x01, 0x0a,
71 0x08, 0x09, 0x8a, 0x13,
72 0x0a, 0x09, 0xc5, 0x11,
73 0x0c, 0x09, 0x86, 0x85,
74 0x0e, 0x09, 0x20, 0x0a,
75 0x10, 0x09, 0x21, 0x0a,
76 0x12, 0x09, 0x41, 0xff,
77 0x14, 0x09, 0x82, 0x00,
78 0x16, 0x09, 0x82, 0x7b,
79 0x18, 0x09, 0x8a, 0x7d,
80 0x1a, 0x09, 0x88, 0x81,
81 0x1c, 0x09, 0x86, 0x7a,
82 0x1e, 0x09, 0x84, 0x81,
83 0x20, 0x09, 0x82, 0x7c,
84 0x22, 0x09, 0x0a, 0x0a
87 static Byte_t RRegData[RREGDATASIZE]=
89 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
90 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
91 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
92 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
93 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
94 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
95 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
96 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
97 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
98 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
99 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
100 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
101 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
105 /* IRQ number to MUDBAC register 2 mapping */
108 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
112 Byte_t rp_sBitMapClrTbl[8] =
114 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
117 Byte_t rp_sBitMapSetTbl[8] =
119 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
122 static void rpfree(void *);
124 /***************************************************************************
125 Function: sReadAiopID
126 Purpose: Read the AIOP idenfication number directly from an AIOP.
127 Call: sReadAiopID(CtlP, aiop)
128 CONTROLLER_T *CtlP; Ptr to controller structure
130 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
131 is replace by an identifying number.
132 Flag AIOPID_NULL if no valid AIOP is found
133 Warnings: No context switches are allowed while executing this function.
136 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
138 Byte_t AiopID; /* ID byte from AIOP */
140 rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */
141 rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
142 AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
145 else /* AIOP does not exist */
149 /***************************************************************************
150 Function: sReadAiopNumChan
151 Purpose: Read the number of channels available in an AIOP directly from
153 Call: sReadAiopNumChan(CtlP, aiop)
154 CONTROLLER_T *CtlP; Ptr to controller structure
156 Return: int: The number of channels available
157 Comments: The number of channels is determined by write/reads from identical
158 offsets within the SRAM address spaces for channels 0 and 4.
159 If the channel 4 space is mirrored to channel 0 it is a 4 channel
160 AIOP, otherwise it is an 8 channel.
161 Warnings: No context switches are allowed while executing this function.
163 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
167 rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
168 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */
169 x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
170 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
171 y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
172 if(x != y) /* if different must be 8 chan */
178 /***************************************************************************
180 Purpose: Initialization of a channel and channel structure
181 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
182 CONTROLLER_T *CtlP; Ptr to controller structure
183 CHANNEL_T *ChP; Ptr to channel structure
184 int AiopNum; AIOP number within controller
185 int ChanNum; Channel number within AIOP
186 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
187 number exceeds number of channels available in AIOP.
188 Comments: This function must be called before a channel can be used.
189 Warnings: No range checking on any of the parameters is done.
191 No context switches are allowed while executing this function.
193 int sInitChan( CONTROLLER_T *CtlP,
202 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
203 return(FALSE); /* exceeds num chans in AIOP */
205 /* Channel, AIOP, and controller identifiers */
207 ChP->ChanID = CtlP->AiopID[AiopNum];
208 ChP->AiopNum = AiopNum;
209 ChP->ChanNum = ChanNum;
211 /* Initialize the channel from the RData array */
212 for(i=0; i < RDATASIZE; i+=4)
215 R[1] = RData[i+1] + 0x10 * ChanNum;
218 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
222 for(i=0; i < RREGDATASIZE; i+=4)
224 ChR[i] = RRegData[i];
225 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
226 ChR[i+2] = RRegData[i+2];
227 ChR[i+3] = RRegData[i+3];
230 /* Indexed registers */
231 ChOff = (Word_t)ChanNum * 0x1000;
233 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
234 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
235 ChP->BaudDiv[2] = (Byte_t)BRD9600;
236 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
237 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv));
239 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
240 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
241 ChP->TxControl[2] = 0;
242 ChP->TxControl[3] = 0;
243 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
245 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
246 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
247 ChP->RxControl[2] = 0;
248 ChP->RxControl[3] = 0;
249 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
251 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
252 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
253 ChP->TxEnables[2] = 0;
254 ChP->TxEnables[3] = 0;
255 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables));
257 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
258 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
259 ChP->TxCompare[2] = 0;
260 ChP->TxCompare[3] = 0;
261 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare));
263 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
264 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
265 ChP->TxReplace1[2] = 0;
266 ChP->TxReplace1[3] = 0;
267 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1));
269 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
270 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
271 ChP->TxReplace2[2] = 0;
272 ChP->TxReplace2[3] = 0;
273 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2));
275 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
276 ChP->TxFIFO = ChOff + _TX_FIFO;
278 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
279 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
280 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
281 rp_writech2(ChP,_INDX_DATA,0);
282 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
283 ChP->RxFIFO = ChOff + _RX_FIFO;
285 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
286 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
287 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
288 rp_writech2(ChP,_INDX_DATA,0);
289 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
290 rp_writech2(ChP,_INDX_DATA,0);
291 ChP->TxPrioCnt = ChOff + _TXP_CNT;
292 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
293 rp_writech1(ChP,_INDX_DATA,0);
294 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
295 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
296 rp_writech1(ChP,_INDX_DATA,0);
297 ChP->TxPrioBuf = ChOff + _TXP_BUF;
298 sEnRxProcessor(ChP); /* start the Rx processor */
303 /***************************************************************************
304 Function: sStopRxProcessor
305 Purpose: Stop the receive processor from processing a channel.
306 Call: sStopRxProcessor(ChP)
307 CHANNEL_T *ChP; Ptr to channel structure
309 Comments: The receive processor can be started again with sStartRxProcessor().
310 This function causes the receive processor to skip over the
311 stopped channel. It does not stop it from processing other channels.
313 Warnings: No context switches are allowed while executing this function.
315 Do not leave the receive processor stopped for more than one
318 After calling this function a delay of 4 uS is required to ensure
319 that the receive processor is no longer processing this channel.
321 void sStopRxProcessor(CHANNEL_T *ChP)
329 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
332 /***************************************************************************
333 Function: sFlushRxFIFO
334 Purpose: Flush the Rx FIFO
335 Call: sFlushRxFIFO(ChP)
336 CHANNEL_T *ChP; Ptr to channel structure
338 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
339 while it is being flushed the receive processor is stopped
340 and the transmitter is disabled. After these operations a
341 4 uS delay is done before clearing the pointers to allow
342 the receive processor to stop. These items are handled inside
344 Warnings: No context switches are allowed while executing this function.
346 void sFlushRxFIFO(CHANNEL_T *ChP)
349 Byte_t Ch; /* channel number within AIOP */
350 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
352 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
353 return; /* don't need to flush */
355 RxFIFOEnabled = FALSE;
356 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
358 RxFIFOEnabled = TRUE;
359 sDisRxFIFO(ChP); /* disable it */
360 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
361 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
363 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
364 Ch = (Byte_t)sGetChanNum(ChP);
365 rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
366 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */
367 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
368 rp_writech2(ChP,_INDX_DATA,0);
369 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
370 rp_writech2(ChP,_INDX_DATA,0);
372 sEnRxFIFO(ChP); /* enable Rx FIFO */
375 /***************************************************************************
376 Function: sFlushTxFIFO
377 Purpose: Flush the Tx FIFO
378 Call: sFlushTxFIFO(ChP)
379 CHANNEL_T *ChP; Ptr to channel structure
381 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
382 while it is being flushed the receive processor is stopped
383 and the transmitter is disabled. After these operations a
384 4 uS delay is done before clearing the pointers to allow
385 the receive processor to stop. These items are handled inside
387 Warnings: No context switches are allowed while executing this function.
389 void sFlushTxFIFO(CHANNEL_T *ChP)
392 Byte_t Ch; /* channel number within AIOP */
393 int TxEnabled; /* TRUE if transmitter enabled */
395 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
396 return; /* don't need to flush */
399 if(ChP->TxControl[3] & TX_ENABLE)
402 sDisTransmit(ChP); /* disable transmitter */
404 sStopRxProcessor(ChP); /* stop Rx processor */
405 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
406 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
407 Ch = (Byte_t)sGetChanNum(ChP);
408 rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
409 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */
410 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
411 rp_writech2(ChP,_INDX_DATA,0);
413 sEnTransmit(ChP); /* enable transmitter */
414 sStartRxProcessor(ChP); /* restart Rx processor */
417 /***************************************************************************
418 Function: sWriteTxPrioByte
419 Purpose: Write a byte of priority transmit data to a channel
420 Call: sWriteTxPrioByte(ChP,Data)
421 CHANNEL_T *ChP; Ptr to channel structure
422 Byte_t Data; The transmit data byte
424 Return: int: 1 if the bytes is successfully written, otherwise 0.
426 Comments: The priority byte is transmitted before any data in the Tx FIFO.
428 Warnings: No context switches are allowed while executing this function.
430 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
432 Byte_t DWBuf[4]; /* buffer for double word writes */
434 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
436 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
437 if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
438 return(0); /* nothing sent */
440 le16enc(DWBuf,ChP->TxPrioBuf); /* data byte address */
442 DWBuf[2] = Data; /* data byte value */
443 DWBuf[3] = 0; /* priority buffer pointer */
444 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
446 le16enc(DWBuf,ChP->TxPrioCnt); /* Tx priority count address */
448 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
449 DWBuf[3] = 0; /* priority buffer pointer */
450 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
452 else /* write it to Tx FIFO */
454 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
456 return(1); /* 1 byte sent */
459 /***************************************************************************
460 Function: sEnInterrupts
461 Purpose: Enable one or more interrupts for a channel
462 Call: sEnInterrupts(ChP,Flags)
463 CHANNEL_T *ChP; Ptr to channel structure
464 Word_t Flags: Interrupt enable flags, can be any combination
465 of the following flags:
466 TXINT_EN: Interrupt on Tx FIFO empty
467 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
469 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
470 MCINT_EN: Interrupt on modem input change
471 CHANINT_EN: Allow channel interrupt signal to the AIOP's
472 Interrupt Channel Register.
474 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
475 enabled. If an interrupt enable flag is not set in Flags, that
476 interrupt will not be changed. Interrupts can be disabled with
477 function sDisInterrupts().
479 This function sets the appropriate bit for the channel in the AIOP's
480 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
481 this channel's bit to be set in the AIOP's Interrupt Channel Register.
483 Interrupts must also be globally enabled before channel interrupts
484 will be passed on to the host. This is done with function
487 In some cases it may be desirable to disable interrupts globally but
488 enable channel interrupts. This would allow the global interrupt
489 status register to be used to determine which AIOPs need service.
491 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
493 Byte_t Mask; /* Interrupt Mask Register */
496 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
498 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
500 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
502 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
504 if(Flags & CHANINT_EN)
506 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
507 rp_writech1(ChP,_INT_MASK,Mask);
511 /***************************************************************************
512 Function: sDisInterrupts
513 Purpose: Disable one or more interrupts for a channel
514 Call: sDisInterrupts(ChP,Flags)
515 CHANNEL_T *ChP; Ptr to channel structure
516 Word_t Flags: Interrupt flags, can be any combination
517 of the following flags:
518 TXINT_EN: Interrupt on Tx FIFO empty
519 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
521 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
522 MCINT_EN: Interrupt on modem input change
523 CHANINT_EN: Disable channel interrupt signal to the
524 AIOP's Interrupt Channel Register.
526 Comments: If an interrupt flag is set in Flags, that interrupt will be
527 disabled. If an interrupt flag is not set in Flags, that
528 interrupt will not be changed. Interrupts can be enabled with
529 function sEnInterrupts().
531 This function clears the appropriate bit for the channel in the AIOP's
532 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
533 this channel's bit from being set in the AIOP's Interrupt Channel
536 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
538 Byte_t Mask; /* Interrupt Mask Register */
541 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
542 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
543 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
544 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
546 if(Flags & CHANINT_EN)
548 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
549 rp_writech1(ChP,_INT_MASK,Mask);
553 /*********************************************************************
554 Begin FreeBsd-specific driver code
555 **********************************************************************/
557 #define POLL_INTERVAL (hz / 100)
559 #define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
560 #define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
561 #define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
564 * The top-level routines begin here
567 static void rpclose(struct tty *tp);
568 static void rphardclose(struct tty *tp);
569 static int rpmodem(struct tty *, int, int);
570 static int rpparam(struct tty *, struct termios *);
571 static void rpstart(struct tty *);
572 static int rpioctl(struct tty *, u_long, caddr_t, struct thread *);
573 static int rpopen(struct tty *);
575 static void rp_do_receive(struct rp_port *rp, struct tty *tp,
576 CHANNEL_t *cp, unsigned int ChanStatus)
578 unsigned int CharNStat;
579 int ToRecv, ch, err = 0;
581 ToRecv = sGetRxCnt(cp);
585 /* If status indicates there are errored characters in the
586 FIFO, then enter status mode (a word in FIFO holds
587 characters and status)
590 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
591 if(!(ChanStatus & STATMODE)) {
592 ChanStatus |= STATMODE;
597 if we previously entered status mode then read down the
598 FIFO one word at a time, pulling apart the character and
599 the status. Update error counters depending on status.
602 if(ChanStatus & STATMODE) {
604 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
605 ch = CharNStat & 0xff;
607 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
609 else if (CharNStat & STMPARITYH)
611 else if (CharNStat & STMRCVROVRH) {
616 ttydisc_rint(tp, ch, err);
620 After emtying FIFO in status mode, turn off status mode
623 if(sGetRxCnt(cp) == 0) {
624 sDisRxStatusMode(cp);
627 ToRecv = sGetRxCnt(cp);
629 ch = rp_readch1(cp,sGetTxRxDataIO(cp));
630 ttydisc_rint(tp, ch & 0xff, err);
634 ttydisc_rint_done(tp);
638 static void rp_handle_port(struct rp_port *rp)
642 unsigned int IntMask, ChanStatus;
647 cp = &rp->rp_channel;
649 IntMask = sGetChanIntID(cp);
650 IntMask = IntMask & rp->rp_intmask;
651 ChanStatus = sGetChanStatus(cp);
652 if(IntMask & RXF_TRIG)
653 rp_do_receive(rp, tp, cp, ChanStatus);
654 if(IntMask & DELTA_CD) {
655 if(ChanStatus & CD_ACT) {
656 (void)ttydisc_modem(tp, 1);
658 (void)ttydisc_modem(tp, 0);
661 /* oldcts = rp->rp_cts;
662 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
663 if(oldcts != rp->rp_cts) {
664 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
669 static void rp_do_poll(void *arg)
675 unsigned char CtlMask, AiopMask;
679 tty_lock_assert(tp, MA_OWNED);
681 CtlMask = ctl->ctlmask(ctl);
682 if (CtlMask & (1 << rp->rp_aiop)) {
683 AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop);
684 if (AiopMask & (1 << rp->rp_chan)) {
689 count = sGetTxCnt(&rp->rp_channel);
690 if (count >= 0 && (count <= rp->rp_restart)) {
693 callout_schedule(&rp->rp_timer, POLL_INTERVAL);
696 static struct ttydevsw rp_tty_class = {
697 .tsw_flags = TF_INITLOCK|TF_CALLOUT,
699 .tsw_close = rpclose,
700 .tsw_outwakeup = rpstart,
701 .tsw_ioctl = rpioctl,
702 .tsw_param = rpparam,
703 .tsw_modem = rpmodem,
711 struct rp_port *rp = softc;
712 CONTROLLER_t *ctlp = rp->rp_ctlp;
714 atomic_subtract_32(&ctlp->free, 1);
718 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
722 int aiop, chan, port;
728 unit = device_get_unit(ctlp->dev);
730 printf("RocketPort%d (Version %s) %d ports.\n", unit,
731 RocketPortVersion, num_ports);
733 ctlp->num_ports = num_ports;
734 ctlp->rp = rp = (struct rp_port *)
735 malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
737 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
743 for(aiop=0; aiop < num_aiops; aiop++) {
744 num_chan = sGetAiopNumChan(ctlp, aiop);
745 for(chan=0; chan < num_chan; chan++, port++, rp++) {
746 rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
747 callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
754 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
755 DELTA_CD | DELTA_CTS | DELTA_DSR;
757 ChanStatus = sGetChanStatus(&rp->rp_channel);
759 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
760 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
765 ChanStatus = sGetChanStatus(&rp->rp_channel);
766 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
767 tty_makedev(tp, NULL, "R%r%r", unit, port);
771 mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
772 ctlp->hwmtx_init = 1;
776 rp_releaseresource(ctlp);
782 rp_releaseresource(CONTROLLER_t *ctlp)
787 if (ctlp->rp != NULL) {
788 for (i = 0; i < ctlp->num_ports; i++) {
790 atomic_add_32(&ctlp->free, 1);
791 tty_lock(rp->rp_tty);
792 tty_rel_gone(rp->rp_tty);
794 free(ctlp->rp, M_DEVBUF);
798 while (ctlp->free != 0) {
799 pause("rpwt", hz / 10);
802 if (ctlp->hwmtx_init)
803 mtx_destroy(&ctlp->hwmtx);
807 rpopen(struct tty *tp)
811 unsigned int IntMask, ChanStatus;
818 rp->rp_channel.TxControl[3] =
819 ((rp->rp_channel.TxControl[3]
820 & ~(SET_RTS | SET_DTR)) | flags);
821 rp_writech4(&rp->rp_channel,_INDX_ADDR,
822 le32dec(rp->rp_channel.TxControl));
823 sSetRxTrigger(&rp->rp_channel, TRIG_1);
824 sDisRxStatusMode(&rp->rp_channel);
825 sFlushRxFIFO(&rp->rp_channel);
826 sFlushTxFIFO(&rp->rp_channel);
828 sEnInterrupts(&rp->rp_channel,
829 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
830 sSetRxTrigger(&rp->rp_channel, TRIG_1);
832 sDisRxStatusMode(&rp->rp_channel);
833 sClrTxXOFF(&rp->rp_channel);
835 /* sDisRTSFlowCtl(&rp->rp_channel);
836 sDisCTSFlowCtl(&rp->rp_channel);
838 sDisTxSoftFlowCtl(&rp->rp_channel);
840 sStartRxProcessor(&rp->rp_channel);
842 sEnRxFIFO(&rp->rp_channel);
843 sEnTransmit(&rp->rp_channel);
845 /* sSetDTR(&rp->rp_channel);
846 sSetRTS(&rp->rp_channel);
849 IntMask = sGetChanIntID(&rp->rp_channel);
850 IntMask = IntMask & rp->rp_intmask;
851 ChanStatus = sGetChanStatus(&rp->rp_channel);
853 callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
855 device_busy(rp->rp_ctlp->dev);
860 rpclose(struct tty *tp)
865 callout_stop(&rp->rp_timer);
867 device_unbusy(rp->rp_ctlp->dev);
871 rphardclose(struct tty *tp)
877 cp = &rp->rp_channel;
882 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
885 sDisTxSoftFlowCtl(cp);
889 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
892 if(ISCALLOUT(tp->t_dev)) {
895 tp->t_actout = FALSE;
896 wakeup(&tp->t_actout);
897 wakeup(TSA_CARR_ON(tp));
902 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
909 sSendBreak(&rp->rp_channel);
912 sClrBreak(&rp->rp_channel);
920 rpmodem(struct tty *tp, int sigon, int sigoff)
926 if (sigon != 0 || sigoff != 0) {
930 if (sigoff & SER_DTR)
934 if (sigoff & SER_RTS)
936 rp->rp_channel.TxControl[3] &= ~i;
937 rp->rp_channel.TxControl[3] |= j;
938 rp_writech4(&rp->rp_channel,_INDX_ADDR,
939 le32dec(rp->rp_channel.TxControl));
941 i = sGetChanStatusLo(&rp->rp_channel);
942 j = rp->rp_channel.TxControl[3];
964 {B0, 0}, {B50, BRD50}, {B75, BRD75},
965 {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
966 {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
967 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
968 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
969 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
970 {B57600, BRD57600}, {B76800, BRD76800},
971 {B115200, BRD115200}, {B230400, BRD230400},
975 static int rp_convert_baud(int baud) {
978 for (i = 0; baud_table[i].baud >= 0; i++) {
979 if (baud_table[i].baud == baud)
983 return baud_table[i].conversion;
993 int cflag, iflag, oflag, lflag;
1000 cp = &rp->rp_channel;
1004 devshift = umynor / 32;
1005 devshift = 1 << devshift;
1006 if ( devshift & RPCLOCAL ) {
1014 ospeed = rp_convert_baud(t->c_ispeed);
1015 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1018 if(t->c_ospeed == 0) {
1022 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1024 /* Set baud rate ----- we only pay attention to ispeed */
1027 sSetBaud(cp, ospeed);
1029 if(cflag & CSTOPB) {
1035 if(cflag & PARENB) {
1037 if(cflag & PARODD) {
1046 if((cflag & CSIZE) == CS8) {
1048 rp->rp_imask = 0xFF;
1051 rp->rp_imask = 0x7F;
1054 if(iflag & ISTRIP) {
1055 rp->rp_imask &= 0x7F;
1058 if(cflag & CLOCAL) {
1059 rp->rp_intmask &= ~DELTA_CD;
1061 rp->rp_intmask |= DELTA_CD;
1064 /* Put flow control stuff here */
1066 if(cflag & CCTS_OFLOW) {
1072 if(cflag & CRTS_IFLOW) {
1073 rp->rp_rts_iflow = 1;
1075 rp->rp_rts_iflow = 0;
1078 if(cflag & CRTS_IFLOW) {
1088 rpstart(struct tty *tp)
1094 int i, count, wcount;
1097 cp = &rp->rp_channel;
1098 flags = rp->rp_channel.TxControl[3];
1100 if(rp->rp_xmit_stopped) {
1102 rp->rp_xmit_stopped = 0;
1105 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1106 count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1107 if(xmit_fifo_room > 0) {
1108 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1109 rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1112 rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);