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 <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>
51 #include <sys/kernel.h>
52 #include <machine/resource.h>
53 #include <machine/bus.h>
58 #include <dev/rp/rpreg.h>
59 #include <dev/rp/rpvar.h>
61 static const char RocketPortVersion[] = "3.02";
63 static Byte_t RData[RDATASIZE] =
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
85 static Byte_t RRegData[RREGDATASIZE]=
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 */
103 /* IRQ number to MUDBAC register 2 mapping */
106 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
110 Byte_t rp_sBitMapClrTbl[8] =
112 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
115 Byte_t rp_sBitMapSetTbl[8] =
117 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
120 static void rpfree(void *);
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
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.
134 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
136 Byte_t AiopID; /* ID byte from AIOP */
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;
143 else /* AIOP does not exist */
147 /***************************************************************************
148 Function: sReadAiopNumChan
149 Purpose: Read the number of channels available in an AIOP directly from
151 Call: sReadAiopNumChan(CtlP, aiop)
152 CONTROLLER_T *CtlP; Ptr to controller structure
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.
161 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
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 */
176 /***************************************************************************
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.
189 No context switches are allowed while executing this function.
191 int sInitChan( CONTROLLER_T *CtlP,
200 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
201 return(FALSE); /* exceeds num chans in AIOP */
203 /* Channel, AIOP, and controller identifiers */
205 ChP->ChanID = CtlP->AiopID[AiopNum];
206 ChP->AiopNum = AiopNum;
207 ChP->ChanNum = ChanNum;
209 /* Initialize the channel from the RData array */
210 for(i=0; i < RDATASIZE; i+=4)
213 R[1] = RData[i+1] + 0x10 * ChanNum;
216 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
220 for(i=0; i < RREGDATASIZE; i+=4)
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];
228 /* Indexed registers */
229 ChOff = (Word_t)ChanNum * 0x1000;
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));
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));
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));
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));
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));
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));
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));
273 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
274 ChP->TxFIFO = ChOff + _TX_FIFO;
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;
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 */
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
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.
311 Warnings: No context switches are allowed while executing this function.
313 Do not leave the receive processor stopped for more than one
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.
319 void sStopRxProcessor(CHANNEL_T *ChP)
327 rp_writech4(ChP,_INDX_ADDR,le32dec(R));
330 /***************************************************************************
331 Function: sFlushRxFIFO
332 Purpose: Flush the Rx FIFO
333 Call: sFlushRxFIFO(ChP)
334 CHANNEL_T *ChP; Ptr to channel structure
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
342 Warnings: No context switches are allowed while executing this function.
344 void sFlushRxFIFO(CHANNEL_T *ChP)
347 Byte_t Ch; /* channel number within AIOP */
348 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
350 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
351 return; /* don't need to flush */
353 RxFIFOEnabled = FALSE;
354 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
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 */
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);
370 sEnRxFIFO(ChP); /* enable Rx FIFO */
373 /***************************************************************************
374 Function: sFlushTxFIFO
375 Purpose: Flush the Tx FIFO
376 Call: sFlushTxFIFO(ChP)
377 CHANNEL_T *ChP; Ptr to channel structure
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
385 Warnings: No context switches are allowed while executing this function.
387 void sFlushTxFIFO(CHANNEL_T *ChP)
390 Byte_t Ch; /* channel number within AIOP */
391 int TxEnabled; /* TRUE if transmitter enabled */
393 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
394 return; /* don't need to flush */
397 if(ChP->TxControl[3] & TX_ENABLE)
400 sDisTransmit(ChP); /* disable transmitter */
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);
411 sEnTransmit(ChP); /* enable transmitter */
412 sStartRxProcessor(ChP); /* restart Rx processor */
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
422 Return: int: 1 if the bytes is successfully written, otherwise 0.
424 Comments: The priority byte is transmitted before any data in the Tx FIFO.
426 Warnings: No context switches are allowed while executing this function.
428 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
430 Byte_t DWBuf[4]; /* buffer for double word writes */
432 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
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 */
438 le16enc(DWBuf,ChP->TxPrioBuf); /* data byte address */
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 */
444 le16enc(DWBuf,ChP->TxPrioCnt); /* Tx priority count address */
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 */
450 else /* write it to Tx FIFO */
452 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
454 return(1); /* 1 byte sent */
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
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.
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().
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.
481 Interrupts must also be globally enabled before channel interrupts
482 will be passed on to the host. This is done with function
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.
489 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
491 Byte_t Mask; /* Interrupt Mask Register */
494 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
496 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
498 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
500 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
502 if(Flags & CHANINT_EN)
504 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
505 rp_writech1(ChP,_INT_MASK,Mask);
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
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.
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().
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
534 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
536 Byte_t Mask; /* Interrupt Mask Register */
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));
544 if(Flags & CHANINT_EN)
546 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
547 rp_writech1(ChP,_INT_MASK,Mask);
551 /*********************************************************************
552 Begin FreeBsd-specific driver code
553 **********************************************************************/
555 #define POLL_INTERVAL (hz / 100)
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)
562 * The top-level routines begin here
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 *);
573 static void rp_do_receive(struct rp_port *rp, struct tty *tp,
574 CHANNEL_t *cp, unsigned int ChanStatus)
576 unsigned int CharNStat;
577 int ToRecv, ch, err = 0;
579 ToRecv = sGetRxCnt(cp);
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)
588 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
589 if(!(ChanStatus & STATMODE)) {
590 ChanStatus |= STATMODE;
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.
600 if(ChanStatus & STATMODE) {
602 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
603 ch = CharNStat & 0xff;
605 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
607 else if (CharNStat & STMPARITYH)
609 else if (CharNStat & STMRCVROVRH) {
614 ttydisc_rint(tp, ch, err);
618 After emtying FIFO in status mode, turn off status mode
621 if(sGetRxCnt(cp) == 0) {
622 sDisRxStatusMode(cp);
625 ToRecv = sGetRxCnt(cp);
627 ch = rp_readch1(cp,sGetTxRxDataIO(cp));
628 ttydisc_rint(tp, ch & 0xff, err);
632 ttydisc_rint_done(tp);
636 static void rp_handle_port(struct rp_port *rp)
640 unsigned int IntMask, ChanStatus;
645 cp = &rp->rp_channel;
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);
656 (void)ttydisc_modem(tp, 0);
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);
667 static void rp_do_poll(void *arg)
673 unsigned char CtlMask, AiopMask;
677 tty_lock_assert(tp, MA_OWNED);
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)) {
687 count = sGetTxCnt(&rp->rp_channel);
688 if (count >= 0 && (count <= rp->rp_restart)) {
691 callout_schedule(&rp->rp_timer, POLL_INTERVAL);
694 static struct ttydevsw rp_tty_class = {
695 .tsw_flags = TF_INITLOCK|TF_CALLOUT,
697 .tsw_close = rpclose,
698 .tsw_outwakeup = rpstart,
699 .tsw_ioctl = rpioctl,
700 .tsw_param = rpparam,
701 .tsw_modem = rpmodem,
709 struct rp_port *rp = softc;
710 CONTROLLER_t *ctlp = rp->rp_ctlp;
712 atomic_subtract_32(&ctlp->free, 1);
716 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
720 int aiop, chan, port;
726 unit = device_get_unit(ctlp->dev);
728 printf("RocketPort%d (Version %s) %d ports.\n", unit,
729 RocketPortVersion, num_ports);
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);
735 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
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);
752 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
753 DELTA_CD | DELTA_CTS | DELTA_DSR;
755 ChanStatus = sGetChanStatus(&rp->rp_channel);
757 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
758 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
763 ChanStatus = sGetChanStatus(&rp->rp_channel);
764 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
765 tty_makedev(tp, NULL, "R%r%r", unit, port);
769 mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
770 ctlp->hwmtx_init = 1;
774 rp_releaseresource(ctlp);
780 rp_releaseresource(CONTROLLER_t *ctlp)
785 if (ctlp->rp != NULL) {
786 for (i = 0; i < ctlp->num_ports; i++) {
788 atomic_add_32(&ctlp->free, 1);
789 tty_lock(rp->rp_tty);
790 tty_rel_gone(rp->rp_tty);
792 free(ctlp->rp, M_DEVBUF);
796 while (ctlp->free != 0) {
797 pause("rpwt", hz / 10);
800 if (ctlp->hwmtx_init)
801 mtx_destroy(&ctlp->hwmtx);
805 rpopen(struct tty *tp)
809 unsigned int IntMask, ChanStatus;
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);
826 sEnInterrupts(&rp->rp_channel,
827 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
828 sSetRxTrigger(&rp->rp_channel, TRIG_1);
830 sDisRxStatusMode(&rp->rp_channel);
831 sClrTxXOFF(&rp->rp_channel);
833 /* sDisRTSFlowCtl(&rp->rp_channel);
834 sDisCTSFlowCtl(&rp->rp_channel);
836 sDisTxSoftFlowCtl(&rp->rp_channel);
838 sStartRxProcessor(&rp->rp_channel);
840 sEnRxFIFO(&rp->rp_channel);
841 sEnTransmit(&rp->rp_channel);
843 /* sSetDTR(&rp->rp_channel);
844 sSetRTS(&rp->rp_channel);
847 IntMask = sGetChanIntID(&rp->rp_channel);
848 IntMask = IntMask & rp->rp_intmask;
849 ChanStatus = sGetChanStatus(&rp->rp_channel);
851 callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
853 device_busy(rp->rp_ctlp->dev);
858 rpclose(struct tty *tp)
863 callout_stop(&rp->rp_timer);
865 device_unbusy(rp->rp_ctlp->dev);
869 rphardclose(struct tty *tp)
875 cp = &rp->rp_channel;
880 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
883 sDisTxSoftFlowCtl(cp);
887 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
890 if(ISCALLOUT(tp->t_dev)) {
893 tp->t_actout = FALSE;
894 wakeup(&tp->t_actout);
895 wakeup(TSA_CARR_ON(tp));
900 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
907 sSendBreak(&rp->rp_channel);
910 sClrBreak(&rp->rp_channel);
918 rpmodem(struct tty *tp, int sigon, int sigoff)
924 if (sigon != 0 || sigoff != 0) {
928 if (sigoff & SER_DTR)
932 if (sigoff & SER_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));
939 i = sGetChanStatusLo(&rp->rp_channel);
940 j = rp->rp_channel.TxControl[3];
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},
973 static int rp_convert_baud(int baud) {
976 for (i = 0; baud_table[i].baud >= 0; i++) {
977 if (baud_table[i].baud == baud)
981 return baud_table[i].conversion;
991 int cflag, iflag, oflag, lflag;
998 cp = &rp->rp_channel;
1002 devshift = umynor / 32;
1003 devshift = 1 << devshift;
1004 if ( devshift & RPCLOCAL ) {
1012 ospeed = rp_convert_baud(t->c_ispeed);
1013 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1016 if(t->c_ospeed == 0) {
1020 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1022 /* Set baud rate ----- we only pay attention to ispeed */
1025 sSetBaud(cp, ospeed);
1027 if(cflag & CSTOPB) {
1033 if(cflag & PARENB) {
1035 if(cflag & PARODD) {
1044 if((cflag & CSIZE) == CS8) {
1046 rp->rp_imask = 0xFF;
1049 rp->rp_imask = 0x7F;
1052 if(iflag & ISTRIP) {
1053 rp->rp_imask &= 0x7F;
1056 if(cflag & CLOCAL) {
1057 rp->rp_intmask &= ~DELTA_CD;
1059 rp->rp_intmask |= DELTA_CD;
1062 /* Put flow control stuff here */
1064 if(cflag & CCTS_OFLOW) {
1070 if(cflag & CRTS_IFLOW) {
1071 rp->rp_rts_iflow = 1;
1073 rp->rp_rts_iflow = 0;
1076 if(cflag & CRTS_IFLOW) {
1086 rpstart(struct tty *tp)
1092 int i, count, wcount;
1095 cp = &rp->rp_channel;
1096 flags = rp->rp_channel.TxControl[3];
1098 if(rp->rp_xmit_stopped) {
1100 rp->rp_xmit_stopped = 0;
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]));
1110 rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);