summaryrefslogtreecommitdiffstats
path: root/sys/dev/rp
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/rp')
-rw-r--r--sys/dev/rp/rp.c1685
-rw-r--r--sys/dev/rp/rp_isa.c504
-rw-r--r--sys/dev/rp/rp_pci.c369
-rw-r--r--sys/dev/rp/rpreg.h1015
-rw-r--r--sys/dev/rp/rpvar.h87
5 files changed, 3660 insertions, 0 deletions
diff --git a/sys/dev/rp/rp.c b/sys/dev/rp/rp.c
new file mode 100644
index 0000000..8e96f5b
--- /dev/null
+++ b/sys/dev/rp/rp.c
@@ -0,0 +1,1685 @@
+/*
+ * Copyright (c) Comtrol Corporation <support@comtrol.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted prodived that the follwoing conditions
+ * are met.
+ * 1. Redistributions of source code must retain the above copyright
+ * notive, this list of conditions and the following disclainer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials prodided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Comtrol Corporation.
+ * 4. The name of Comtrol Corporation may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rp.c - for RocketPort FreeBSD
+ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#define ROCKET_C
+#include <dev/rp/rpreg.h>
+#include <dev/rp/rpvar.h>
+
+static const char RocketPortVersion[] = "3.02";
+
+static Byte_t RData[RDATASIZE] =
+{
+ 0x00, 0x09, 0xf6, 0x82,
+ 0x02, 0x09, 0x86, 0xfb,
+ 0x04, 0x09, 0x00, 0x0a,
+ 0x06, 0x09, 0x01, 0x0a,
+ 0x08, 0x09, 0x8a, 0x13,
+ 0x0a, 0x09, 0xc5, 0x11,
+ 0x0c, 0x09, 0x86, 0x85,
+ 0x0e, 0x09, 0x20, 0x0a,
+ 0x10, 0x09, 0x21, 0x0a,
+ 0x12, 0x09, 0x41, 0xff,
+ 0x14, 0x09, 0x82, 0x00,
+ 0x16, 0x09, 0x82, 0x7b,
+ 0x18, 0x09, 0x8a, 0x7d,
+ 0x1a, 0x09, 0x88, 0x81,
+ 0x1c, 0x09, 0x86, 0x7a,
+ 0x1e, 0x09, 0x84, 0x81,
+ 0x20, 0x09, 0x82, 0x7c,
+ 0x22, 0x09, 0x0a, 0x0a
+};
+
+static Byte_t RRegData[RREGDATASIZE]=
+{
+ 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
+ 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
+ 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
+ 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
+ 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
+ 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
+ 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
+ 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
+ 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
+ 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
+ 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
+ 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
+ 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
+};
+
+#if 0
+/* IRQ number to MUDBAC register 2 mapping */
+Byte_t sIRQMap[16] =
+{
+ 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
+};
+#endif
+
+Byte_t rp_sBitMapClrTbl[8] =
+{
+ 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
+};
+
+Byte_t rp_sBitMapSetTbl[8] =
+{
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
+};
+
+/* Actually not used */
+#if notdef
+struct termios deftermios = {
+ TTYDEF_IFLAG,
+ TTYDEF_OFLAG,
+ TTYDEF_CFLAG,
+ TTYDEF_LFLAG,
+ { CEOF, CEOL, CEOL, CERASE, CWERASE, CKILL, CREPRINT,
+ _POSIX_VDISABLE, CINTR, CQUIT, CSUSP, CDSUSP, CSTART, CSTOP, CLNEXT,
+ CDISCARD, CMIN, CTIME, CSTATUS, _POSIX_VDISABLE },
+ TTYDEF_SPEED,
+ TTYDEF_SPEED
+};
+#endif
+
+/***************************************************************************
+Function: sReadAiopID
+Purpose: Read the AIOP idenfication number directly from an AIOP.
+Call: sReadAiopID(CtlP, aiop)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int aiop: AIOP index
+Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
+ is replace by an identifying number.
+ Flag AIOPID_NULL if no valid AIOP is found
+Warnings: No context switches are allowed while executing this function.
+
+*/
+int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
+{
+ Byte_t AiopID; /* ID byte from AIOP */
+
+ rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */
+ rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
+ AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
+ if(AiopID == 0x06)
+ return(1);
+ else /* AIOP does not exist */
+ return(-1);
+}
+
+/***************************************************************************
+Function: sReadAiopNumChan
+Purpose: Read the number of channels available in an AIOP directly from
+ an AIOP.
+Call: sReadAiopNumChan(CtlP, aiop)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int aiop: AIOP index
+Return: int: The number of channels available
+Comments: The number of channels is determined by write/reads from identical
+ offsets within the SRAM address spaces for channels 0 and 4.
+ If the channel 4 space is mirrored to channel 0 it is a 4 channel
+ AIOP, otherwise it is an 8 channel.
+Warnings: No context switches are allowed while executing this function.
+*/
+int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
+{
+ Word_t x, y;
+
+ rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
+ rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */
+ x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
+ rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
+ y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
+ if(x != y) /* if different must be 8 chan */
+ return(8);
+ else
+ return(4);
+}
+
+/***************************************************************************
+Function: sInitChan
+Purpose: Initialization of a channel and channel structure
+Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ CHANNEL_T *ChP; Ptr to channel structure
+ int AiopNum; AIOP number within controller
+ int ChanNum; Channel number within AIOP
+Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
+ number exceeds number of channels available in AIOP.
+Comments: This function must be called before a channel can be used.
+Warnings: No range checking on any of the parameters is done.
+
+ No context switches are allowed while executing this function.
+*/
+int sInitChan( CONTROLLER_T *CtlP,
+ CHANNEL_T *ChP,
+ int AiopNum,
+ int ChanNum)
+{
+ int i, ChOff;
+ Byte_t *ChR;
+ static Byte_t R[4];
+
+ if(ChanNum >= CtlP->AiopNumChan[AiopNum])
+ return(FALSE); /* exceeds num chans in AIOP */
+
+ /* Channel, AIOP, and controller identifiers */
+ ChP->CtlP = CtlP;
+ ChP->ChanID = CtlP->AiopID[AiopNum];
+ ChP->AiopNum = AiopNum;
+ ChP->ChanNum = ChanNum;
+
+ /* Initialize the channel from the RData array */
+ for(i=0; i < RDATASIZE; i+=4)
+ {
+ R[0] = RData[i];
+ R[1] = RData[i+1] + 0x10 * ChanNum;
+ R[2] = RData[i+2];
+ R[3] = RData[i+3];
+ rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)&R[0]));
+ }
+
+ ChR = ChP->R;
+ for(i=0; i < RREGDATASIZE; i+=4)
+ {
+ ChR[i] = RRegData[i];
+ ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
+ ChR[i+2] = RRegData[i+2];
+ ChR[i+3] = RRegData[i+3];
+ }
+
+ /* Indexed registers */
+ ChOff = (Word_t)ChanNum * 0x1000;
+
+ ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
+ ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
+ ChP->BaudDiv[2] = (Byte_t)BRD9600;
+ ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->BaudDiv[0]);
+
+ ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
+ ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
+ ChP->TxControl[2] = 0;
+ ChP->TxControl[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
+
+ ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
+ ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
+ ChP->RxControl[2] = 0;
+ ChP->RxControl[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
+
+ ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
+ ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
+ ChP->TxEnables[2] = 0;
+ ChP->TxEnables[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxEnables[0]);
+
+ ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
+ ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
+ ChP->TxCompare[2] = 0;
+ ChP->TxCompare[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxCompare[0]);
+
+ ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
+ ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
+ ChP->TxReplace1[2] = 0;
+ ChP->TxReplace1[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace1[0]);
+
+ ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
+ ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
+ ChP->TxReplace2[2] = 0;
+ ChP->TxReplace2[3] = 0;
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace2[0]);
+
+ ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
+ ChP->TxFIFO = ChOff + _TX_FIFO;
+
+ rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
+ rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
+ rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
+ rp_writech2(ChP,_INDX_DATA,0);
+ ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
+ ChP->RxFIFO = ChOff + _RX_FIFO;
+
+ rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
+ rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
+ rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
+ rp_writech2(ChP,_INDX_DATA,0);
+ rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
+ rp_writech2(ChP,_INDX_DATA,0);
+ ChP->TxPrioCnt = ChOff + _TXP_CNT;
+ rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
+ rp_writech1(ChP,_INDX_DATA,0);
+ ChP->TxPrioPtr = ChOff + _TXP_PNTR;
+ rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
+ rp_writech1(ChP,_INDX_DATA,0);
+ ChP->TxPrioBuf = ChOff + _TXP_BUF;
+ sEnRxProcessor(ChP); /* start the Rx processor */
+
+ return(TRUE);
+}
+
+/***************************************************************************
+Function: sStopRxProcessor
+Purpose: Stop the receive processor from processing a channel.
+Call: sStopRxProcessor(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+
+Comments: The receive processor can be started again with sStartRxProcessor().
+ This function causes the receive processor to skip over the
+ stopped channel. It does not stop it from processing other channels.
+
+Warnings: No context switches are allowed while executing this function.
+
+ Do not leave the receive processor stopped for more than one
+ character time.
+
+ After calling this function a delay of 4 uS is required to ensure
+ that the receive processor is no longer processing this channel.
+*/
+void sStopRxProcessor(CHANNEL_T *ChP)
+{
+ Byte_t R[4];
+
+ R[0] = ChP->R[0];
+ R[1] = ChP->R[1];
+ R[2] = 0x0a;
+ R[3] = ChP->R[3];
+ rp_writech4(ChP, _INDX_ADDR,*(DWord_t *)&R[0]);
+}
+
+/***************************************************************************
+Function: sFlushRxFIFO
+Purpose: Flush the Rx FIFO
+Call: sFlushRxFIFO(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: void
+Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
+ while it is being flushed the receive processor is stopped
+ and the transmitter is disabled. After these operations a
+ 4 uS delay is done before clearing the pointers to allow
+ the receive processor to stop. These items are handled inside
+ this function.
+Warnings: No context switches are allowed while executing this function.
+*/
+void sFlushRxFIFO(CHANNEL_T *ChP)
+{
+ int i;
+ Byte_t Ch; /* channel number within AIOP */
+ int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
+
+ if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
+ return; /* don't need to flush */
+
+ RxFIFOEnabled = FALSE;
+ if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
+ {
+ RxFIFOEnabled = TRUE;
+ sDisRxFIFO(ChP); /* disable it */
+ for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
+ rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
+ }
+ sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
+ Ch = (Byte_t)sGetChanNum(ChP);
+ rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
+ rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */
+ rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
+ rp_writech2(ChP,_INDX_DATA,0);
+ rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
+ rp_writech2(ChP,_INDX_DATA,0);
+ if(RxFIFOEnabled)
+ sEnRxFIFO(ChP); /* enable Rx FIFO */
+}
+
+/***************************************************************************
+Function: sFlushTxFIFO
+Purpose: Flush the Tx FIFO
+Call: sFlushTxFIFO(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: void
+Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
+ while it is being flushed the receive processor is stopped
+ and the transmitter is disabled. After these operations a
+ 4 uS delay is done before clearing the pointers to allow
+ the receive processor to stop. These items are handled inside
+ this function.
+Warnings: No context switches are allowed while executing this function.
+*/
+void sFlushTxFIFO(CHANNEL_T *ChP)
+{
+ int i;
+ Byte_t Ch; /* channel number within AIOP */
+ int TxEnabled; /* TRUE if transmitter enabled */
+
+ if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
+ return; /* don't need to flush */
+
+ TxEnabled = FALSE;
+ if(ChP->TxControl[3] & TX_ENABLE)
+ {
+ TxEnabled = TRUE;
+ sDisTransmit(ChP); /* disable transmitter */
+ }
+ sStopRxProcessor(ChP); /* stop Rx processor */
+ for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
+ rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */
+ Ch = (Byte_t)sGetChanNum(ChP);
+ rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
+ rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */
+ rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
+ rp_writech2(ChP,_INDX_DATA,0);
+ if(TxEnabled)
+ sEnTransmit(ChP); /* enable transmitter */
+ sStartRxProcessor(ChP); /* restart Rx processor */
+}
+
+/***************************************************************************
+Function: sWriteTxPrioByte
+Purpose: Write a byte of priority transmit data to a channel
+Call: sWriteTxPrioByte(ChP,Data)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Data; The transmit data byte
+
+Return: int: 1 if the bytes is successfully written, otherwise 0.
+
+Comments: The priority byte is transmitted before any data in the Tx FIFO.
+
+Warnings: No context switches are allowed while executing this function.
+*/
+int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
+{
+ Byte_t DWBuf[4]; /* buffer for double word writes */
+ Word_t *WordPtr; /* must be far because Win SS != DS */
+
+ if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
+ {
+ rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
+ if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
+ return(0); /* nothing sent */
+
+ WordPtr = (Word_t *)(&DWBuf[0]);
+ *WordPtr = ChP->TxPrioBuf; /* data byte address */
+
+ DWBuf[2] = Data; /* data byte value */
+ rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
+
+ *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
+
+ DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
+ DWBuf[3] = 0; /* priority buffer pointer */
+ rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
+ }
+ else /* write it to Tx FIFO */
+ {
+ sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
+ }
+ return(1); /* 1 byte sent */
+}
+
+/***************************************************************************
+Function: sEnInterrupts
+Purpose: Enable one or more interrupts for a channel
+Call: sEnInterrupts(ChP,Flags)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Word_t Flags: Interrupt enable flags, can be any combination
+ of the following flags:
+ TXINT_EN: Interrupt on Tx FIFO empty
+ RXINT_EN: Interrupt on Rx FIFO at trigger level (see
+ sSetRxTrigger())
+ SRCINT_EN: Interrupt on SRC (Special Rx Condition)
+ MCINT_EN: Interrupt on modem input change
+ CHANINT_EN: Allow channel interrupt signal to the AIOP's
+ Interrupt Channel Register.
+Return: void
+Comments: If an interrupt enable flag is set in Flags, that interrupt will be
+ enabled. If an interrupt enable flag is not set in Flags, that
+ interrupt will not be changed. Interrupts can be disabled with
+ function sDisInterrupts().
+
+ This function sets the appropriate bit for the channel in the AIOP's
+ Interrupt Mask Register if the CHANINT_EN flag is set. This allows
+ this channel's bit to be set in the AIOP's Interrupt Channel Register.
+
+ Interrupts must also be globally enabled before channel interrupts
+ will be passed on to the host. This is done with function
+ sEnGlobalInt().
+
+ In some cases it may be desirable to disable interrupts globally but
+ enable channel interrupts. This would allow the global interrupt
+ status register to be used to determine which AIOPs need service.
+*/
+void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
+{
+ Byte_t Mask; /* Interrupt Mask Register */
+
+ ChP->RxControl[2] |=
+ ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
+
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
+
+ ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
+
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
+
+ if(Flags & CHANINT_EN)
+ {
+ Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
+ rp_writech1(ChP,_INT_MASK,Mask);
+ }
+}
+
+/***************************************************************************
+Function: sDisInterrupts
+Purpose: Disable one or more interrupts for a channel
+Call: sDisInterrupts(ChP,Flags)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Word_t Flags: Interrupt flags, can be any combination
+ of the following flags:
+ TXINT_EN: Interrupt on Tx FIFO empty
+ RXINT_EN: Interrupt on Rx FIFO at trigger level (see
+ sSetRxTrigger())
+ SRCINT_EN: Interrupt on SRC (Special Rx Condition)
+ MCINT_EN: Interrupt on modem input change
+ CHANINT_EN: Disable channel interrupt signal to the
+ AIOP's Interrupt Channel Register.
+Return: void
+Comments: If an interrupt flag is set in Flags, that interrupt will be
+ disabled. If an interrupt flag is not set in Flags, that
+ interrupt will not be changed. Interrupts can be enabled with
+ function sEnInterrupts().
+
+ This function clears the appropriate bit for the channel in the AIOP's
+ Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
+ this channel's bit from being set in the AIOP's Interrupt Channel
+ Register.
+*/
+void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
+{
+ Byte_t Mask; /* Interrupt Mask Register */
+
+ ChP->RxControl[2] &=
+ ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
+ ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
+
+ if(Flags & CHANINT_EN)
+ {
+ Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
+ rp_writech1(ChP,_INT_MASK,Mask);
+ }
+}
+
+/*********************************************************************
+ Begin FreeBsd-specific driver code
+**********************************************************************/
+
+static timeout_t rpdtrwakeup;
+
+static d_open_t rpopen;
+static d_close_t rpclose;
+static d_write_t rpwrite;
+static d_ioctl_t rpioctl;
+
+#define CDEV_MAJOR 81
+struct cdevsw rp_cdevsw = {
+ .d_open = rpopen,
+ .d_close = rpclose,
+ .d_read = ttyread,
+ .d_write = rpwrite,
+ .d_ioctl = rpioctl,
+ .d_poll = ttypoll,
+ .d_name = "rp",
+ .d_maj = CDEV_MAJOR,
+ .d_flags = D_TTY,
+};
+
+static int rp_num_ports_open = 0;
+static int rp_ndevs = 0;
+static int minor_to_unit[128];
+
+static int rp_num_ports[4]; /* Number of ports on each controller */
+
+#define POLL_INTERVAL 1
+
+#define CALLOUT_MASK 0x80
+#define CONTROL_MASK 0x60
+#define CONTROL_INIT_STATE 0x20
+#define CONTROL_LOCK_STATE 0x40
+#define DEV_UNIT(dev) (MINOR_TO_UNIT(minor(dev))
+#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
+#define MINOR_MAGIC(dev) ((minor(dev)) & ~MINOR_MAGIC_MASK)
+#define IS_CALLOUT(dev) (minor(dev) & CALLOUT_MASK)
+#define IS_CONTROL(dev) (minor(dev) & CONTROL_MASK)
+
+#define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
+#define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
+#define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
+
+static struct rp_port *p_rp_addr[4];
+static struct rp_port *p_rp_table[MAX_RP_PORTS];
+#define rp_addr(unit) (p_rp_addr[unit])
+#define rp_table(port) (p_rp_table[port])
+
+/*
+ * The top-level routines begin here
+ */
+
+static int rpparam(struct tty *, struct termios *);
+static void rpstart(struct tty *);
+static void rpstop(struct tty *, int);
+static void rphardclose (struct rp_port *);
+static void rp_disc_optim (struct tty *tp, struct termios *t);
+
+static void rp_do_receive(struct rp_port *rp, struct tty *tp,
+ CHANNEL_t *cp, unsigned int ChanStatus)
+{
+ int spl;
+ unsigned int CharNStat;
+ int ToRecv, wRecv, ch, ttynocopy;
+
+ ToRecv = sGetRxCnt(cp);
+ if(ToRecv == 0)
+ return;
+
+/* If status indicates there are errored characters in the
+ FIFO, then enter status mode (a word in FIFO holds
+ characters and status)
+*/
+
+ if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
+ if(!(ChanStatus & STATMODE)) {
+ ChanStatus |= STATMODE;
+ sEnRxStatusMode(cp);
+ }
+ }
+/*
+ if we previously entered status mode then read down the
+ FIFO one word at a time, pulling apart the character and
+ the status. Update error counters depending on status.
+*/
+ if(ChanStatus & STATMODE) {
+ while(ToRecv) {
+ if(tp->t_state & TS_TBLOCK) {
+ break;
+ }
+ CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
+ ch = CharNStat & 0xff;
+
+ if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
+ ch |= TTY_FE;
+ else if (CharNStat & STMPARITYH)
+ ch |= TTY_PE;
+ else if (CharNStat & STMRCVROVRH)
+ rp->rp_overflows++;
+
+ (*linesw[tp->t_line].l_rint)(ch, tp);
+ ToRecv--;
+ }
+/*
+ After emtying FIFO in status mode, turn off status mode
+*/
+
+ if(sGetRxCnt(cp) == 0) {
+ sDisRxStatusMode(cp);
+ }
+ } else {
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ ToRecv = sGetRxCnt(cp);
+ if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
+ if ( ToRecv > RXFIFO_SIZE ) {
+ ToRecv = RXFIFO_SIZE;
+ }
+ wRecv = ToRecv >> 1;
+ if ( wRecv ) {
+ rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
+ }
+ if ( ToRecv & 1 ) {
+ ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
+ }
+ tk_nin += ToRecv;
+ tk_rawcc += ToRecv;
+ tp->t_rawcc += ToRecv;
+ ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
+ ttwakeup(tp);
+ } else {
+ while (ToRecv) {
+ if(tp->t_state & TS_TBLOCK) {
+ break;
+ }
+ ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
+ spl = spltty();
+ (*linesw[tp->t_line].l_rint)(ch, tp);
+ splx(spl);
+ ToRecv--;
+ }
+ }
+ }
+}
+
+static void rp_handle_port(struct rp_port *rp)
+{
+ CHANNEL_t *cp;
+ struct tty *tp;
+ unsigned int IntMask, ChanStatus;
+
+ if(!rp)
+ return;
+
+ cp = &rp->rp_channel;
+ tp = rp->rp_tty;
+ IntMask = sGetChanIntID(cp);
+ IntMask = IntMask & rp->rp_intmask;
+ ChanStatus = sGetChanStatus(cp);
+ if(IntMask & RXF_TRIG)
+ if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
+ rp_do_receive(rp, tp, cp, ChanStatus);
+ }
+ if(IntMask & DELTA_CD) {
+ if(ChanStatus & CD_ACT) {
+ if(!(tp->t_state & TS_CARR_ON) ) {
+ (void)(*linesw[tp->t_line].l_modem)(tp, 1);
+ }
+ } else {
+ if((tp->t_state & TS_CARR_ON)) {
+ (void)(*linesw[tp->t_line].l_modem)(tp, 0);
+ if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
+ rphardclose(rp);
+ }
+ }
+ }
+ }
+/* oldcts = rp->rp_cts;
+ rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
+ if(oldcts != rp->rp_cts) {
+ printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
+ }
+*/
+}
+
+static void rp_do_poll(void *not_used)
+{
+ CONTROLLER_t *ctl;
+ struct rp_port *rp;
+ struct tty *tp;
+ int unit, aiop, ch, line, count;
+ unsigned char CtlMask, AiopMask;
+
+ for(unit = 0; unit < rp_ndevs; unit++) {
+ rp = rp_addr(unit);
+ ctl = rp->rp_ctlp;
+ CtlMask = ctl->ctlmask(ctl);
+ for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
+ if(CtlMask & 1) {
+ AiopMask = sGetAiopIntStatus(ctl, aiop);
+ for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
+ if(AiopMask & 1) {
+ line = (unit << 5) | (aiop << 3) | ch;
+ rp = rp_table(line);
+ rp_handle_port(rp);
+ }
+ }
+ }
+ }
+
+ for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
+ line++, rp++) {
+ tp = rp->rp_tty;
+ if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
+ count = sGetTxCnt(&rp->rp_channel);
+ if(count == 0)
+ tp->t_state &= ~(TS_BUSY);
+ if(!(tp->t_state & TS_TTSTOP) &&
+ (count <= rp->rp_restart)) {
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+ }
+ }
+ }
+ if(rp_num_ports_open)
+ timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
+}
+
+int
+rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
+{
+ int oldspl, unit;
+ int num_chan;
+ int aiop, chan, port;
+ int ChanStatus, line, i, count;
+ int retval;
+ struct rp_port *rp;
+ struct tty *tty;
+ dev_t *dev_nodes;
+
+ unit = device_get_unit(ctlp->dev);
+
+ printf("RocketPort%d (Version %s) %d ports.\n", unit,
+ RocketPortVersion, num_ports);
+ rp_num_ports[unit] = num_ports;
+
+ ctlp->rp = rp = (struct rp_port *)
+ malloc(sizeof(struct rp_port) * num_ports, M_TTYS, M_NOWAIT);
+ if (rp == NULL) {
+ device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ count = unit * 32; /* board times max ports per card SG */
+ for(i=count;i < (count + rp_num_ports[unit]);i++)
+ minor_to_unit[i] = unit;
+
+ bzero(rp, sizeof(struct rp_port) * num_ports);
+ ctlp->tty = tty = (struct tty *)
+ malloc(sizeof(struct tty) * num_ports, M_TTYS,
+ M_NOWAIT | M_ZERO);
+ if(tty == NULL) {
+ device_printf(ctlp->dev, "rp_attachcommon: Could not malloc tty structures.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ oldspl = spltty();
+ rp_addr(unit) = rp;
+ splx(oldspl);
+
+ dev_nodes = ctlp->dev_nodes = malloc(sizeof(*(ctlp->dev_nodes)) * rp_num_ports[unit] * 6, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if(ctlp->dev_nodes == NULL) {
+ device_printf(ctlp->dev, "rp_attachcommon: Could not malloc device node structures.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ for (i = 0 ; i < rp_num_ports[unit] ; i++) {
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i,
+ UID_ROOT, GID_WHEEL, 0666, "ttyR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x20,
+ UID_ROOT, GID_WHEEL, 0666, "ttyiR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x40,
+ UID_ROOT, GID_WHEEL, 0666, "ttylR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0x80,
+ UID_ROOT, GID_WHEEL, 0666, "cuaR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xa0,
+ UID_ROOT, GID_WHEEL, 0666, "cuaiR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ *(dev_nodes++) = make_dev(&rp_cdevsw, ((unit + 1) << 16) | i | 0xc0,
+ UID_ROOT, GID_WHEEL, 0666, "cualR%c",
+ i <= 9 ? '0' + i : 'a' + i - 10);
+ }
+
+ port = 0;
+ for(aiop=0; aiop < num_aiops; aiop++) {
+ num_chan = sGetAiopNumChan(ctlp, aiop);
+ for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
+ rp->rp_tty = tty;
+ rp->rp_port = port;
+ rp->rp_ctlp = ctlp;
+ rp->rp_unit = unit;
+ rp->rp_chan = chan;
+ rp->rp_aiop = aiop;
+
+ tty->t_line = 0;
+ /* tty->t_termios = deftermios;
+ */
+ rp->dtr_wait = 3 * hz;
+ rp->it_in.c_iflag = 0;
+ rp->it_in.c_oflag = 0;
+ rp->it_in.c_cflag = TTYDEF_CFLAG;
+ rp->it_in.c_lflag = 0;
+ termioschars(&rp->it_in);
+ /* termioschars(&tty->t_termios);
+ */
+ rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
+ rp->it_out = rp->it_in;
+
+ rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
+ DELTA_CD | DELTA_CTS | DELTA_DSR;
+#if notdef
+ ChanStatus = sGetChanStatus(&rp->rp_channel);
+#endif /* notdef */
+ if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
+ device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
+ unit, aiop, chan);
+ retval = ENXIO;
+ goto nogo;
+ }
+ ChanStatus = sGetChanStatus(&rp->rp_channel);
+ rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
+ line = (unit << 5) | (aiop << 3) | chan;
+ rp_table(line) = rp;
+ }
+ }
+
+ rp_ndevs++;
+ return (0);
+
+nogo:
+ rp_releaseresource(ctlp);
+
+ return (retval);
+}
+
+void
+rp_releaseresource(CONTROLLER_t *ctlp)
+{
+ int i, s, unit;
+
+ unit = device_get_unit(ctlp->dev);
+
+ if (ctlp->rp != NULL) {
+ s = spltty();
+ for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
+ if (p_rp_addr[i] == ctlp->rp)
+ p_rp_addr[i] = NULL;
+ for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
+ if (p_rp_table[i] == ctlp->rp)
+ p_rp_table[i] = NULL;
+ splx(s);
+ free(ctlp->rp, M_DEVBUF);
+ ctlp->rp = NULL;
+ }
+ if (ctlp->tty != NULL) {
+ free(ctlp->tty, M_DEVBUF);
+ ctlp->tty = NULL;
+ }
+ if (ctlp->dev != NULL) {
+ for (i = 0 ; i < rp_num_ports[unit] * 6 ; i++)
+ destroy_dev(ctlp->dev_nodes[i]);
+ free(ctlp->dev_nodes, M_DEVBUF);
+ ctlp->dev = NULL;
+ }
+}
+
+static int
+rpopen(dev, flag, mode, td)
+ dev_t dev;
+ int flag, mode;
+ struct thread *td;
+{
+ struct rp_port *rp;
+ int unit, port, mynor, umynor, flags; /* SG */
+ struct tty *tp;
+ int oldspl, error;
+ unsigned int IntMask, ChanStatus;
+
+
+ umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
+ port = (minor(dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor];
+ if (rp_addr(unit) == NULL)
+ return (ENXIO);
+ if(IS_CONTROL(dev))
+ return(0);
+ rp = rp_addr(unit) + port;
+/* rp->rp_tty = &rp_tty[rp->rp_port];
+*/
+ tp = rp->rp_tty;
+ dev->si_tty = tp;
+
+ oldspl = spltty();
+
+open_top:
+ while(rp->state & ~SET_DTR) {
+ error = tsleep(&rp->dtr_wait, TTIPRI | PCATCH, "rpdtr", 0);
+ if(error != 0)
+ goto out;
+ }
+
+ if(tp->t_state & TS_ISOPEN) {
+ if(IS_CALLOUT(dev)) {
+ if(!rp->active_out) {
+ error = EBUSY;
+ goto out;
+ }
+ } else {
+ if(rp->active_out) {
+ if(flag & O_NONBLOCK) {
+ error = EBUSY;
+ goto out;
+ }
+ error = tsleep(&rp->active_out,
+ TTIPRI | PCATCH, "rpbi", 0);
+ if(error != 0)
+ goto out;
+ goto open_top;
+ }
+ }
+ if(tp->t_state & TS_XCLUDE && suser(td) != 0) {
+ splx(oldspl);
+ error = EBUSY;
+ goto out2;
+ }
+ }
+ else {
+ tp->t_dev = dev;
+ tp->t_param = rpparam;
+ tp->t_oproc = rpstart;
+ tp->t_stop = rpstop;
+ tp->t_line = 0;
+ tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
+ tp->t_ififosize = 512;
+ tp->t_ispeedwat = (speed_t)-1;
+ tp->t_ospeedwat = (speed_t)-1;
+ flags = 0;
+ flags |= SET_RTS;
+ flags |= SET_DTR;
+ rp->rp_channel.TxControl[3] =
+ ((rp->rp_channel.TxControl[3]
+ & ~(SET_RTS | SET_DTR)) | flags);
+ rp_writech4(&rp->rp_channel,_INDX_ADDR,
+ *(DWord_t *) &(rp->rp_channel.TxControl[0]));
+ sSetRxTrigger(&rp->rp_channel, TRIG_1);
+ sDisRxStatusMode(&rp->rp_channel);
+ sFlushRxFIFO(&rp->rp_channel);
+ sFlushTxFIFO(&rp->rp_channel);
+
+ sEnInterrupts(&rp->rp_channel,
+ (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
+ sSetRxTrigger(&rp->rp_channel, TRIG_1);
+
+ sDisRxStatusMode(&rp->rp_channel);
+ sClrTxXOFF(&rp->rp_channel);
+
+/* sDisRTSFlowCtl(&rp->rp_channel);
+ sDisCTSFlowCtl(&rp->rp_channel);
+*/
+ sDisTxSoftFlowCtl(&rp->rp_channel);
+
+ sStartRxProcessor(&rp->rp_channel);
+
+ sEnRxFIFO(&rp->rp_channel);
+ sEnTransmit(&rp->rp_channel);
+
+/* sSetDTR(&rp->rp_channel);
+ sSetRTS(&rp->rp_channel);
+*/
+
+ ++rp->wopeners;
+ error = rpparam(tp, &tp->t_termios);
+ --rp->wopeners;
+ if(error != 0) {
+ splx(oldspl);
+ return(error);
+ }
+
+ rp_num_ports_open++;
+
+ IntMask = sGetChanIntID(&rp->rp_channel);
+ IntMask = IntMask & rp->rp_intmask;
+ ChanStatus = sGetChanStatus(&rp->rp_channel);
+ if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
+ if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
+ (void)(*linesw[tp->t_line].l_modem)(tp, 1);
+ }
+ }
+
+ if(rp_num_ports_open == 1)
+ timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
+
+ }
+
+ if(!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
+ !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
+ ++rp->wopeners;
+ error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "rpdcd", 0);
+ --rp->wopeners;
+ if(error != 0)
+ goto out;
+ goto open_top;
+ }
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+
+ rp_disc_optim(tp, &tp->t_termios);
+ if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
+ rp->active_out = TRUE;
+
+/* if(rp_num_ports_open == 1)
+ timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL);
+*/
+out:
+ splx(oldspl);
+ if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
+ rphardclose(rp);
+ }
+out2:
+ if (error == 0)
+ device_busy(rp->rp_ctlp->dev);
+ return(error);
+}
+
+static int
+rpclose(dev, flag, mode, td)
+ dev_t dev;
+ int flag, mode;
+ struct thread *td;
+{
+ int oldspl, unit, mynor, umynor, port; /* SG */
+ struct rp_port *rp;
+ struct tty *tp;
+ CHANNEL_t *cp;
+
+ umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
+ port = (minor(dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor]; /* SG */
+
+ if(IS_CONTROL(dev))
+ return(0);
+ rp = rp_addr(unit) + port;
+ cp = &rp->rp_channel;
+ tp = rp->rp_tty;
+
+ oldspl = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ rp_disc_optim(tp, &tp->t_termios);
+ rpstop(tp, FREAD | FWRITE);
+ rphardclose(rp);
+
+ tp->t_state &= ~TS_BUSY;
+ ttyclose(tp);
+
+ splx(oldspl);
+
+ device_unbusy(rp->rp_ctlp->dev);
+
+ return(0);
+}
+
+static void
+rphardclose(struct rp_port *rp)
+{
+ int mynor;
+ struct tty *tp;
+ CHANNEL_t *cp;
+
+ cp = &rp->rp_channel;
+ tp = rp->rp_tty;
+ mynor = MINOR_MAGIC(tp->t_dev);
+
+ sFlushRxFIFO(cp);
+ sFlushTxFIFO(cp);
+ sDisTransmit(cp);
+ sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
+ sDisRTSFlowCtl(cp);
+ sDisCTSFlowCtl(cp);
+ sDisTxSoftFlowCtl(cp);
+ sClrTxXOFF(cp);
+
+ if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
+ sClrDTR(cp);
+ }
+ if(IS_CALLOUT(tp->t_dev)) {
+ sClrDTR(cp);
+ }
+ if(rp->dtr_wait != 0) {
+ timeout(rpdtrwakeup, rp, rp->dtr_wait);
+ rp->state |= ~SET_DTR;
+ }
+
+ rp->active_out = FALSE;
+ wakeup(&rp->active_out);
+ wakeup(TSA_CARR_ON(tp));
+}
+
+static
+int
+rpwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct rp_port *rp;
+ struct tty *tp;
+ int unit, mynor, port, umynor, error = 0; /* SG */
+
+ umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
+ port = (minor(dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor]; /* SG */
+
+ if(IS_CONTROL(dev))
+ return(ENODEV);
+ rp = rp_addr(unit) + port;
+ tp = rp->rp_tty;
+ while(rp->rp_disable_writes) {
+ rp->rp_waiting = 1;
+ error = ttysleep(tp, (caddr_t)rp, TTOPRI|PCATCH, "rp_write", 0);
+ if (error)
+ return(error);
+ }
+
+ error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
+ return error;
+}
+
+static void
+rpdtrwakeup(void *chan)
+{
+ struct rp_port *rp;
+
+ rp = (struct rp_port *)chan;
+ rp->state &= SET_DTR;
+ wakeup(&rp->dtr_wait);
+}
+
+static int
+rpioctl(dev, cmd, data, flag, td)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct thread *td;
+{
+ struct rp_port *rp;
+ CHANNEL_t *cp;
+ struct tty *tp;
+ int unit, mynor, port, umynor; /* SG */
+ int oldspl;
+ int error = 0;
+ int arg, flags, result, ChanStatus;
+ struct termios *t;
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ u_long oldcmd;
+ struct termios term;
+#endif
+
+ umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
+ port = (minor(dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor];
+ rp = rp_addr(unit) + port;
+
+ if(IS_CONTROL(dev)) {
+ struct termios *ct;
+
+ switch (IS_CONTROL(dev)) {
+ case CONTROL_INIT_STATE:
+ ct = IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
+ break;
+ case CONTROL_LOCK_STATE:
+ ct = IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
+ break;
+ default:
+ return(ENODEV); /* /dev/nodev */
+ }
+ switch (cmd) {
+ case TIOCSETA:
+ error = suser(td);
+ if(error != 0)
+ return(error);
+ *ct = *(struct termios *)data;
+ return(0);
+ case TIOCGETA:
+ *(struct termios *)data = *ct;
+ return(0);
+ case TIOCGETD:
+ *(int *)data = TTYDISC;
+ return(0);
+ case TIOCGWINSZ:
+ bzero(data, sizeof(struct winsize));
+ return(0);
+ default:
+ return(ENOTTY);
+ }
+ }
+
+ tp = rp->rp_tty;
+ cp = &rp->rp_channel;
+
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
+ term = tp->t_termios;
+ oldcmd = cmd;
+ error = ttsetcompat(tp, &cmd, data, &term);
+ if(error != 0)
+ return(error);
+ if(cmd != oldcmd) {
+ data = (caddr_t)&term;
+ }
+#endif
+ if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
+ int cc;
+ struct termios *dt = (struct termios *)data;
+ struct termios *lt = IS_CALLOUT(dev)
+ ? &rp->lt_out : &rp->lt_in;
+
+ dt->c_iflag = (tp->t_iflag & lt->c_iflag)
+ | (dt->c_iflag & ~lt->c_iflag);
+ dt->c_oflag = (tp->t_oflag & lt->c_oflag)
+ | (dt->c_oflag & ~lt->c_oflag);
+ dt->c_cflag = (tp->t_cflag & lt->c_cflag)
+ | (dt->c_cflag & ~lt->c_cflag);
+ dt->c_lflag = (tp->t_lflag & lt->c_lflag)
+ | (dt->c_lflag & ~lt->c_lflag);
+ for(cc = 0; cc < NCCS; ++cc)
+ if(lt->c_cc[cc] != 0)
+ dt->c_cc[cc] = tp->t_cc[cc];
+ if(lt->c_ispeed != 0)
+ dt->c_ispeed = tp->t_ispeed;
+ if(lt->c_ospeed != 0)
+ dt->c_ospeed = tp->t_ospeed;
+ }
+
+ t = &tp->t_termios;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
+ if(error != ENOIOCTL) {
+ return(error);
+ }
+ oldspl = spltty();
+
+ flags = rp->rp_channel.TxControl[3];
+
+ error = ttioctl(tp, cmd, data, flag);
+ flags = rp->rp_channel.TxControl[3];
+ rp_disc_optim(tp, &tp->t_termios);
+ if(error != ENOIOCTL) {
+ splx(oldspl);
+ return(error);
+ }
+ switch(cmd) {
+ case TIOCSBRK:
+ sSendBreak(&rp->rp_channel);
+ break;
+
+ case TIOCCBRK:
+ sClrBreak(&rp->rp_channel);
+ break;
+
+ case TIOCSDTR:
+ sSetDTR(&rp->rp_channel);
+ sSetRTS(&rp->rp_channel);
+ break;
+
+ case TIOCCDTR:
+ sClrDTR(&rp->rp_channel);
+ break;
+
+ case TIOCMSET:
+ arg = *(int *) data;
+ flags = 0;
+ if(arg & TIOCM_RTS)
+ flags |= SET_RTS;
+ if(arg & TIOCM_DTR)
+ flags |= SET_DTR;
+ rp->rp_channel.TxControl[3] =
+ ((rp->rp_channel.TxControl[3]
+ & ~(SET_RTS | SET_DTR)) | flags);
+ rp_writech4(&rp->rp_channel,_INDX_ADDR,
+ *(DWord_t *) &(rp->rp_channel.TxControl[0]));
+ break;
+ case TIOCMBIS:
+ arg = *(int *) data;
+ flags = 0;
+ if(arg & TIOCM_RTS)
+ flags |= SET_RTS;
+ if(arg & TIOCM_DTR)
+ flags |= SET_DTR;
+ rp->rp_channel.TxControl[3] |= flags;
+ rp_writech4(&rp->rp_channel,_INDX_ADDR,
+ *(DWord_t *) &(rp->rp_channel.TxControl[0]));
+ break;
+ case TIOCMBIC:
+ arg = *(int *) data;
+ flags = 0;
+ if(arg & TIOCM_RTS)
+ flags |= SET_RTS;
+ if(arg & TIOCM_DTR)
+ flags |= SET_DTR;
+ rp->rp_channel.TxControl[3] &= ~flags;
+ rp_writech4(&rp->rp_channel,_INDX_ADDR,
+ *(DWord_t *) &(rp->rp_channel.TxControl[0]));
+ break;
+
+
+ case TIOCMGET:
+ ChanStatus = sGetChanStatusLo(&rp->rp_channel);
+ flags = rp->rp_channel.TxControl[3];
+ result = TIOCM_LE; /* always on while open for some reason */
+ result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
+ | ((flags & SET_RTS) ? TIOCM_RTS : 0)
+ | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
+ | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
+ | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
+
+ if(rp->rp_channel.RxControl[2] & RTSFC_EN)
+ {
+ result |= TIOCM_RTS;
+ }
+
+ *(int *)data = result;
+ break;
+ case TIOCMSDTRWAIT:
+ error = suser(td);
+ if(error != 0) {
+ splx(oldspl);
+ return(error);
+ }
+ rp->dtr_wait = *(int *)data * hz/100;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = rp->dtr_wait * 100/hz;
+ break;
+ default:
+ splx(oldspl);
+ return ENOTTY;
+ }
+ splx(oldspl);
+ return(0);
+}
+
+static struct speedtab baud_table[] = {
+ {B0, 0}, {B50, BRD50}, {B75, BRD75},
+ {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
+ {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
+ {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
+ {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
+ {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
+ {B57600, BRD57600}, {B76800, BRD76800},
+ {B115200, BRD115200}, {B230400, BRD230400},
+ {-1, -1}
+};
+
+static int
+rpparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct rp_port *rp;
+ CHANNEL_t *cp;
+ int unit, mynor, port, umynor; /* SG */
+ int oldspl, cflag, iflag, oflag, lflag;
+ int ospeed;
+#ifdef RPCLOCAL
+ int devshift;
+#endif
+
+
+ umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
+ port = (minor(tp->t_dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+
+ unit = minor_to_unit[mynor];
+ rp = rp_addr(unit) + port;
+ cp = &rp->rp_channel;
+ oldspl = spltty();
+
+ cflag = t->c_cflag;
+#ifdef RPCLOCAL
+ devshift = umynor / 32;
+ devshift = 1 << devshift;
+ if ( devshift & RPCLOCAL ) {
+ cflag |= CLOCAL;
+ }
+#endif
+ iflag = t->c_iflag;
+ oflag = t->c_oflag;
+ lflag = t->c_lflag;
+
+ ospeed = ttspeedtab(t->c_ispeed, baud_table);
+ if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
+ return(EINVAL);
+
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ tp->t_iflag = iflag;
+ tp->t_oflag = oflag;
+ tp->t_lflag = lflag;
+
+ if(t->c_ospeed == 0) {
+ sClrDTR(cp);
+ return(0);
+ }
+ rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
+
+ /* Set baud rate ----- we only pay attention to ispeed */
+ sSetDTR(cp);
+ sSetRTS(cp);
+ sSetBaud(cp, ospeed);
+
+ if(cflag & CSTOPB) {
+ sSetStop2(cp);
+ } else {
+ sSetStop1(cp);
+ }
+
+ if(cflag & PARENB) {
+ sEnParity(cp);
+ if(cflag & PARODD) {
+ sSetOddParity(cp);
+ } else {
+ sSetEvenParity(cp);
+ }
+ }
+ else {
+ sDisParity(cp);
+ }
+ if((cflag & CSIZE) == CS8) {
+ sSetData8(cp);
+ rp->rp_imask = 0xFF;
+ } else {
+ sSetData7(cp);
+ rp->rp_imask = 0x7F;
+ }
+
+ if(iflag & ISTRIP) {
+ rp->rp_imask &= 0x7F;
+ }
+
+ if(cflag & CLOCAL) {
+ rp->rp_intmask &= ~DELTA_CD;
+ } else {
+ rp->rp_intmask |= DELTA_CD;
+ }
+
+ /* Put flow control stuff here */
+
+ if(cflag & CCTS_OFLOW) {
+ sEnCTSFlowCtl(cp);
+ } else {
+ sDisCTSFlowCtl(cp);
+ }
+
+ if(cflag & CRTS_IFLOW) {
+ rp->rp_rts_iflow = 1;
+ } else {
+ rp->rp_rts_iflow = 0;
+ }
+
+ if(cflag & CRTS_IFLOW) {
+ sEnRTSFlowCtl(cp);
+ } else {
+ sDisRTSFlowCtl(cp);
+ }
+ rp_disc_optim(tp, t);
+
+ if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
+ tp->t_state |= TS_CARR_ON;
+ wakeup(TSA_CARR_ON(tp));
+ }
+
+/* tp->t_state |= TS_CAN_BYPASS_L_RINT;
+ flags = rp->rp_channel.TxControl[3];
+ if(flags & SET_DTR)
+ else
+ if(flags & SET_RTS)
+ else
+*/
+ splx(oldspl);
+
+ return(0);
+}
+
+static void
+rp_disc_optim(tp, t)
+struct tty *tp;
+struct termios *t;
+{
+ if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
+ &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
+ &&(!(t->c_iflag & PARMRK)
+ ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
+ && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
+ && linesw[tp->t_line].l_rint == ttyinput)
+ tp->t_state |= TS_CAN_BYPASS_L_RINT;
+ else
+ tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
+}
+
+static void
+rpstart(tp)
+ struct tty *tp;
+{
+ struct rp_port *rp;
+ CHANNEL_t *cp;
+ struct clist *qp;
+ int unit, mynor, port, umynor; /* SG */
+ char flags;
+ int spl, xmit_fifo_room;
+ int count, wcount;
+
+
+ umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
+ port = (minor(tp->t_dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor];
+ rp = rp_addr(unit) + port;
+ cp = &rp->rp_channel;
+ flags = rp->rp_channel.TxControl[3];
+ spl = spltty();
+
+ if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
+ ttwwakeup(tp);
+ splx(spl);
+ return;
+ }
+ if(rp->rp_xmit_stopped) {
+ sEnTransmit(cp);
+ rp->rp_xmit_stopped = 0;
+ }
+ count = sGetTxCnt(cp);
+
+ if(tp->t_outq.c_cc == 0) {
+ if((tp->t_state & TS_BUSY) && (count == 0)) {
+ tp->t_state &= ~TS_BUSY;
+ }
+ ttwwakeup(tp);
+ splx(spl);
+ return;
+ }
+ xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
+ qp = &tp->t_outq;
+ if(xmit_fifo_room > 0 && qp->c_cc > 0) {
+ tp->t_state |= TS_BUSY;
+ count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
+ wcount = count >> 1;
+ if ( wcount ) {
+ rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
+ }
+ if ( count & 1 ) {
+ rp_writech1(cp, sGetTxRxDataIO(cp),
+ ((unsigned char *)(rp->TxBuf))[(count-1)]);
+ }
+ }
+ rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
+
+ ttwwakeup(tp);
+ splx(spl);
+}
+
+static
+void
+rpstop(tp, flag)
+ register struct tty *tp;
+ int flag;
+{
+ struct rp_port *rp;
+ CHANNEL_t *cp;
+ int unit, mynor, port, umynor; /* SG */
+ int spl;
+
+ umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
+ port = (minor(tp->t_dev) & 0x1f); /* SG */
+ mynor = (port + umynor); /* SG */
+ unit = minor_to_unit[mynor];
+ rp = rp_addr(unit) + port;
+ cp = &rp->rp_channel;
+
+ spl = spltty();
+
+ if(tp->t_state & TS_BUSY) {
+ if((tp->t_state&TS_TTSTOP) == 0) {
+ sFlushTxFIFO(cp);
+ } else {
+ if(rp->rp_xmit_stopped == 0) {
+ sDisTransmit(cp);
+ rp->rp_xmit_stopped = 1;
+ }
+ }
+ }
+ splx(spl);
+ rpstart(tp);
+}
diff --git a/sys/dev/rp/rp_isa.c b/sys/dev/rp/rp_isa.c
new file mode 100644
index 0000000..7277195
--- /dev/null
+++ b/sys/dev/rp/rp_isa.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) Comtrol Corporation <support@comtrol.com>
+ * All rights reserved.
+ *
+ * ISA-specific part separated from:
+ * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted prodived that the follwoing conditions
+ * are met.
+ * 1. Redistributions of source code must retain the above copyright
+ * notive, this list of conditions and the following disclainer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials prodided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Comtrol Corporation.
+ * 4. The name of Comtrol Corporation may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#define ROCKET_C
+#include <dev/rp/rpreg.h>
+#include <dev/rp/rpvar.h>
+
+#include <isa/isavar.h>
+
+/* ISA-specific part of CONTROLLER_t */
+struct ISACONTROLLER_T {
+ int MBaseIO; /* rid of the Mudbac controller for this controller */
+ int MReg0IO; /* offset0 of the Mudbac controller for this controller */
+ int MReg1IO; /* offset1 of the Mudbac controller for this controller */
+ int MReg2IO; /* offset2 of the Mudbac controller for this controller */
+ int MReg3IO; /* offset3 of the Mudbac controller for this controller */
+ Byte_t MReg2;
+ Byte_t MReg3;
+};
+typedef struct ISACONTROLLER_T ISACONTROLLER_t;
+
+#define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp))
+
+/***************************************************************************
+Function: sControllerEOI
+Purpose: Strobe the MUDBAC's End Of Interrupt bit.
+Call: sControllerEOI(MudbacCtlP,CtlP)
+ CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
+ CONTROLLER_T *CtlP; Ptr to controller structure
+*/
+#define sControllerEOI(MudbacCtlP,CtlP) \
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB)
+
+/***************************************************************************
+Function: sDisAiop
+Purpose: Disable I/O access to an AIOP
+Call: sDisAiop(MudbacCtlP,CtlP)
+ CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int AiopNum; Number of AIOP on controller
+*/
+#define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \
+{ \
+ ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
+}
+
+/***************************************************************************
+Function: sEnAiop
+Purpose: Enable I/O access to an AIOP
+Call: sEnAiop(MudbacCtlP,CtlP)
+ CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int AiopNum; Number of AIOP on controller
+*/
+#define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \
+{ \
+ ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
+}
+
+/***************************************************************************
+Function: sGetControllerIntStatus
+Purpose: Get the controller interrupt status
+Call: sGetControllerIntStatus(MudbacCtlP,CtlP)
+ CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
+ CONTROLLER_T *CtlP; Ptr to controller structure
+Return: Byte_t: The controller interrupt status in the lower 4
+ bits. Bits 0 through 3 represent AIOP's 0
+ through 3 respectively. If a bit is set that
+ AIOP is interrupting. Bits 4 through 7 will
+ always be cleared.
+*/
+#define sGetControllerIntStatus(MudbacCtlP,CtlP) \
+ (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f)
+
+static devclass_t rp_devclass;
+static CONTROLLER_t *rp_controller;
+static int rp_nisadevs;
+
+static int rp_probe(device_t dev);
+static int rp_attach(device_t dev);
+static void rp_isareleaseresource(CONTROLLER_t *ctlp);
+static int sInitController(CONTROLLER_T *CtlP,
+ CONTROLLER_T *MudbacCtlP,
+ int AiopNum,
+ int IRQNum,
+ Byte_t Frequency,
+ int PeriodicOnly);
+static rp_aiop2rid_t rp_isa_aiop2rid;
+static rp_aiop2off_t rp_isa_aiop2off;
+static rp_ctlmask_t rp_isa_ctlmask;
+
+static int
+rp_probe(device_t dev)
+{
+ int unit;
+ CONTROLLER_t *controller;
+ int num_aiops;
+ CONTROLLER_t *ctlp;
+ int retval;
+
+ /*
+ * We have no PnP RocketPort cards.
+ * (At least according to LINT)
+ */
+ if (isa_get_logicalid(dev) != 0)
+ return (ENXIO);
+
+ /* We need IO port resource to configure an ISA device. */
+ if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0)
+ return (ENXIO);
+
+ unit = device_get_unit(dev);
+ if (unit >= 4) {
+ device_printf(dev, "rpprobe: unit number %d invalid.\n", unit);
+ return (ENXIO);
+ }
+ device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit);
+
+ ctlp = device_get_softc(dev);
+ bzero(ctlp, sizeof(*ctlp));
+ ctlp->dev = dev;
+ ctlp->aiop2rid = rp_isa_aiop2rid;
+ ctlp->aiop2off = rp_isa_aiop2off;
+ ctlp->ctlmask = rp_isa_ctlmask;
+
+ /* The IO ports of AIOPs for an ISA controller are discrete. */
+ ctlp->io_num = 1;
+ ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO);
+ ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctlp->io_rid == NULL || ctlp->io == NULL) {
+ device_printf(dev, "rp_attach: Out of memory.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctlp->bus_ctlp == NULL) {
+ device_printf(dev, "rp_attach: Out of memory.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ ctlp->io_rid[0] = 0;
+ if (rp_controller != NULL) {
+ controller = rp_controller;
+ ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x40, RF_ACTIVE);
+ } else {
+ controller = rp_controller = ctlp;
+ ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x44, RF_ACTIVE);
+ }
+ if (ctlp->io[0] == NULL) {
+ device_printf(dev, "rp_attach: Resource not available.\n");
+ retval = ENXIO;
+ goto nogo;
+ }
+
+ num_aiops = sInitController(ctlp,
+ controller,
+ MAX_AIOPS_PER_BOARD, 0,
+ FREQ_DIS, 0);
+ if (num_aiops <= 0) {
+ device_printf(dev, "board%d init failed.\n", unit);
+ retval = ENXIO;
+ goto nogo;
+ }
+
+ if (rp_controller == NULL)
+ rp_controller = controller;
+ rp_nisadevs++;
+
+ device_set_desc(dev, "RocketPort ISA");
+
+ return (0);
+
+nogo:
+ rp_isareleaseresource(ctlp);
+
+ return (retval);
+}
+
+static int
+rp_attach(device_t dev)
+{
+ int unit;
+ int num_ports, num_aiops;
+ int aiop;
+ CONTROLLER_t *ctlp;
+ int retval;
+
+ unit = device_get_unit(dev);
+
+ ctlp = device_get_softc(dev);
+
+#if notdef
+ num_aiops = sInitController(ctlp,
+ rp_controller,
+ MAX_AIOPS_PER_BOARD, 0,
+ FREQ_DIS, 0);
+#else
+ num_aiops = ctlp->NumAiop;
+#endif /* notdef */
+
+ num_ports = 0;
+ for(aiop=0; aiop < num_aiops; aiop++) {
+ sResetAiopByNum(ctlp, aiop);
+ sEnAiop(rp_controller, ctlp, aiop);
+ num_ports += sGetAiopNumChan(ctlp, aiop);
+ }
+
+ retval = rp_attachcommon(ctlp, num_aiops, num_ports);
+ if (retval != 0)
+ goto nogo;
+
+ return (0);
+
+nogo:
+ rp_isareleaseresource(ctlp);
+
+ return (retval);
+}
+
+static void
+rp_isareleaseresource(CONTROLLER_t *ctlp)
+{
+ int i;
+
+ rp_releaseresource(ctlp);
+
+ if (ctlp == rp_controller)
+ rp_controller = NULL;
+ if (ctlp->io != NULL) {
+ for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++)
+ if (ctlp->io[i] != NULL)
+ bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]);
+ free(ctlp->io, M_DEVBUF);
+ }
+ if (ctlp->io_rid != NULL)
+ free(ctlp->io_rid, M_DEVBUF);
+ if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) {
+ bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]);
+ rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL;
+ rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0;
+ }
+ if (ctlp->bus_ctlp != NULL)
+ free(ctlp->bus_ctlp, M_DEVBUF);
+}
+
+/***************************************************************************
+Function: sInitController
+Purpose: Initialization of controller global registers and controller
+ structure.
+Call: sInitController(CtlP,MudbacCtlP,AiopNum,
+ IRQNum,Frequency,PeriodicOnly)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
+ int AiopNum; Number of Aiops
+ int IRQNum; Interrupt Request number. Can be any of the following:
+ 0: Disable global interrupts
+ 3: IRQ 3
+ 4: IRQ 4
+ 5: IRQ 5
+ 9: IRQ 9
+ 10: IRQ 10
+ 11: IRQ 11
+ 12: IRQ 12
+ 15: IRQ 15
+ Byte_t Frequency: A flag identifying the frequency
+ of the periodic interrupt, can be any one of the following:
+ FREQ_DIS - periodic interrupt disabled
+ FREQ_137HZ - 137 Hertz
+ FREQ_69HZ - 69 Hertz
+ FREQ_34HZ - 34 Hertz
+ FREQ_17HZ - 17 Hertz
+ FREQ_9HZ - 9 Hertz
+ FREQ_4HZ - 4 Hertz
+ If IRQNum is set to 0 the Frequency parameter is
+ overidden, it is forced to a value of FREQ_DIS.
+ int PeriodicOnly: TRUE if all interrupts except the periodic
+ interrupt are to be blocked.
+ FALSE is both the periodic interrupt and
+ other channel interrupts are allowed.
+ If IRQNum is set to 0 the PeriodicOnly parameter is
+ overidden, it is forced to a value of FALSE.
+Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
+ initialization failed.
+
+Comments:
+ If periodic interrupts are to be disabled but AIOP interrupts
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+
+ If interrupts are to be completely disabled set IRQNum to 0.
+
+ Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+ invalid combination.
+
+ This function performs initialization of global interrupt modes,
+ but it does not actually enable global interrupts. To enable
+ and disable global interrupts use functions sEnGlobalInt() and
+ sDisGlobalInt(). Enabling of global interrupts is normally not
+ done until all other initializations are complete.
+
+ Even if interrupts are globally enabled, they must also be
+ individually enabled for each channel that is to generate
+ interrupts.
+
+Warnings: No range checking on any of the parameters is done.
+
+ No context switches are allowed while executing this function.
+
+ After this function all AIOPs on the controller are disabled,
+ they can be enabled with sEnAiop().
+*/
+static int
+sInitController( CONTROLLER_T *CtlP,
+ CONTROLLER_T *MudbacCtlP,
+ int AiopNum,
+ int IRQNum,
+ Byte_t Frequency,
+ int PeriodicOnly)
+{
+ int i;
+ int ctl_base, aiop_base, aiop_size;
+
+ CtlP->CtlID = CTLID_0001; /* controller release 1 */
+
+ ISACTL(CtlP)->MBaseIO = rp_nisadevs;
+ if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) {
+ ISACTL(CtlP)->MReg0IO = 0x40 + 0;
+ ISACTL(CtlP)->MReg1IO = 0x40 + 1;
+ ISACTL(CtlP)->MReg2IO = 0x40 + 2;
+ ISACTL(CtlP)->MReg3IO = 0x40 + 3;
+ } else {
+ MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO;
+ ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs;
+ MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] = bus_alloc_resource(MudbacCtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[ISACTL(CtlP)->MBaseIO], ctl_base, ctl_base + 3, 4, RF_ACTIVE);
+ ISACTL(CtlP)->MReg0IO = 0;
+ ISACTL(CtlP)->MReg1IO = 1;
+ ISACTL(CtlP)->MReg2IO = 2;
+ ISACTL(CtlP)->MReg3IO = 3;
+ }
+#if 1
+ ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
+ ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
+#else
+ if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */
+ {
+ ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
+ ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
+ }
+ else
+ {
+ ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
+ ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */
+ if(PeriodicOnly) /* periodic interrupt only */
+ {
+ ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY;
+ }
+ }
+#endif
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2);
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3);
+ sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */
+
+ /* Init AIOPs */
+ CtlP->NumAiop = 0;
+ for(i=0; i < AiopNum; i++)
+ {
+ if (CtlP->io[i] == NULL) {
+ CtlP->io_rid[i] = i;
+ aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i;
+ if (rp_nisadevs == 0)
+ aiop_size = 0x44;
+ else
+ aiop_size = 0x40;
+ CtlP->io[i] = bus_alloc_resource(CtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[i], aiop_base, aiop_base + aiop_size - 1, aiop_size, RF_ACTIVE);
+ } else
+ aiop_base = rman_get_start(CtlP->io[i]);
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
+ ISACTL(CtlP)->MReg2IO,
+ ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */
+ rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
+ ISACTL(CtlP)->MReg0IO,
+ (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */
+ sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */
+
+ CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */
+ if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
+ {
+ sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
+ bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]);
+ CtlP->io[i] = NULL;
+ break; /* done looking for AIOPs */
+ }
+
+ CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */
+ rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */
+ rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC);
+ CtlP->NumAiop++; /* bump count of AIOPs */
+ sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
+ }
+
+ if(CtlP->NumAiop == 0)
+ return(-1);
+ else
+ return(CtlP->NumAiop);
+}
+
+/*
+ * ARGSUSED
+ * Maps (aiop, offset) to rid.
+ */
+static int
+rp_isa_aiop2rid(int aiop, int offset)
+{
+ /* rid equals to aiop for an ISA controller. */
+ return aiop;
+}
+
+/*
+ * ARGSUSED
+ * Maps (aiop, offset) to the offset of resource.
+ */
+static int
+rp_isa_aiop2off(int aiop, int offset)
+{
+ /* Each aiop has its own resource. */
+ return offset;
+}
+
+/* Read the int status for an ISA controller. */
+static unsigned char
+rp_isa_ctlmask(CONTROLLER_t *ctlp)
+{
+ return sGetControllerIntStatus(rp_controller,ctlp);
+}
+
+static device_method_t rp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rp_probe),
+ DEVMETHOD(device_attach, rp_attach),
+
+ { 0, 0 }
+};
+
+static driver_t rp_driver = {
+ "rp",
+ rp_methods,
+ sizeof(CONTROLLER_t),
+};
+
+/*
+ * rp can be attached to an isa bus.
+ */
+DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0);
diff --git a/sys/dev/rp/rp_pci.c b/sys/dev/rp/rp_pci.c
new file mode 100644
index 0000000..b7c1ad7
--- /dev/null
+++ b/sys/dev/rp/rp_pci.c
@@ -0,0 +1,369 @@
+/*-
+ * Copyright (c) Comtrol Corporation <support@comtrol.com>
+ * All rights reserved.
+ *
+ * PCI-specific part separated from:
+ * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted prodived that the follwoing conditions
+ * are met.
+ * 1. Redistributions of source code must retain the above copyright
+ * notive, this list of conditions and the following disclainer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials prodided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Comtrol Corporation.
+ * 4. The name of Comtrol Corporation may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#define ROCKET_C
+#include <dev/rp/rpreg.h>
+#include <dev/rp/rpvar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+/* PCI IDs */
+#define RP_VENDOR_ID 0x11FE
+#define RP_DEVICE_ID_32I 0x0001
+#define RP_DEVICE_ID_8I 0x0002
+#define RP_DEVICE_ID_16I 0x0003
+#define RP_DEVICE_ID_4Q 0x0004
+#define RP_DEVICE_ID_8O 0x0005
+#define RP_DEVICE_ID_8J 0x0006
+#define RP_DEVICE_ID_4J 0x0007
+#define RP_DEVICE_ID_6M 0x000C
+#define RP_DEVICE_ID_4M 0x000D
+
+/**************************************************************************
+ MUDBAC remapped for PCI
+**************************************************************************/
+
+#define _CFG_INT_PCI 0x40
+#define _PCI_INT_FUNC 0x3A
+
+#define PCI_STROB 0x2000
+#define INTR_EN_PCI 0x0010
+
+/***************************************************************************
+Function: sPCIControllerEOI
+Purpose: Strobe the MUDBAC's End Of Interrupt bit.
+Call: sPCIControllerEOI(CtlP)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+*/
+#define sPCIControllerEOI(CtlP) rp_writeio2(CtlP, 0, _PCI_INT_FUNC, PCI_STROB)
+
+/***************************************************************************
+Function: sPCIGetControllerIntStatus
+Purpose: Get the controller interrupt status
+Call: sPCIGetControllerIntStatus(CtlP)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+Return: Byte_t: The controller interrupt status in the lower 4
+ bits. Bits 0 through 3 represent AIOP's 0
+ through 3 respectively. If a bit is set that
+ AIOP is interrupting. Bits 4 through 7 will
+ always be cleared.
+*/
+#define sPCIGetControllerIntStatus(CTLP) ((rp_readio2(CTLP, 0, _PCI_INT_FUNC) >> 8) & 0x1f)
+
+static devclass_t rp_devclass;
+
+static int rp_pciprobe(device_t dev);
+static int rp_pciattach(device_t dev);
+#if notdef
+static int rp_pcidetach(device_t dev);
+static int rp_pcishutdown(device_t dev);
+#endif /* notdef */
+static void rp_pcireleaseresource(CONTROLLER_t *ctlp);
+static int sPCIInitController( CONTROLLER_t *CtlP,
+ int AiopNum,
+ int IRQNum,
+ Byte_t Frequency,
+ int PeriodicOnly,
+ int VendorDevice);
+static rp_aiop2rid_t rp_pci_aiop2rid;
+static rp_aiop2off_t rp_pci_aiop2off;
+static rp_ctlmask_t rp_pci_ctlmask;
+
+/*
+ * The following functions are the pci-specific part
+ * of rp driver.
+ */
+
+static int
+rp_pciprobe(device_t dev)
+{
+ char *s;
+
+ s = NULL;
+ if ((pci_get_devid(dev) & 0xffff) == RP_VENDOR_ID)
+ s = "RocketPort PCI";
+
+ if (s != NULL) {
+ device_set_desc(dev, s);
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+static int
+rp_pciattach(device_t dev)
+{
+ int num_ports, num_aiops;
+ int aiop;
+ CONTROLLER_t *ctlp;
+ int unit;
+ int retval;
+ u_int32_t stcmd;
+
+ ctlp = device_get_softc(dev);
+ bzero(ctlp, sizeof(*ctlp));
+ ctlp->dev = dev;
+ unit = device_get_unit(dev);
+ ctlp->aiop2rid = rp_pci_aiop2rid;
+ ctlp->aiop2off = rp_pci_aiop2off;
+ ctlp->ctlmask = rp_pci_ctlmask;
+
+ /* Wake up the device. */
+ stcmd = pci_read_config(dev, PCIR_COMMAND, 4);
+ if ((stcmd & PCIM_CMD_PORTEN) == 0) {
+ stcmd |= (PCIM_CMD_PORTEN);
+ pci_write_config(dev, PCIR_COMMAND, 4, stcmd);
+ }
+
+ /* The IO ports of AIOPs for a PCI controller are continuous. */
+ ctlp->io_num = 1;
+ ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO);
+ ctlp->io = malloc(sizeof(*(ctlp->io)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (ctlp->io_rid == NULL || ctlp->io == NULL) {
+ device_printf(dev, "rp_pciattach: Out of memory.\n");
+ retval = ENOMEM;
+ goto nogo;
+ }
+
+ ctlp->bus_ctlp = NULL;
+
+ ctlp->io_rid[0] = 0x10;
+ ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 1, RF_ACTIVE);
+ if(ctlp->io[0] == NULL) {
+ device_printf(dev, "ioaddr mapping failed for RocketPort(PCI).\n");
+ retval = ENXIO;
+ goto nogo;
+ }
+
+ num_aiops = sPCIInitController(ctlp,
+ MAX_AIOPS_PER_BOARD, 0,
+ FREQ_DIS, 0, (pci_get_devid(dev) >> 16) & 0xffff);
+
+ num_ports = 0;
+ for(aiop=0; aiop < num_aiops; aiop++) {
+ sResetAiopByNum(ctlp, aiop);
+ num_ports += sGetAiopNumChan(ctlp, aiop);
+ }
+
+ retval = rp_attachcommon(ctlp, num_aiops, num_ports);
+ if (retval != 0)
+ goto nogo;
+
+ return (0);
+
+nogo:
+ rp_pcireleaseresource(ctlp);
+
+ return (retval);
+}
+
+#if notdef
+static int
+rp_pcidetach(device_t dev)
+{
+ CONTROLLER_t *ctlp;
+
+ if (device_get_state(dev) == DS_BUSY)
+ return (EBUSY);
+
+ ctlp = device_get_softc(dev);
+
+ rp_pcireleaseresource(ctlp);
+
+ return (0);
+}
+
+static int
+rp_pcishutdown(device_t dev)
+{
+ CONTROLLER_t *ctlp;
+
+ if (device_get_state(dev) == DS_BUSY)
+ return (EBUSY);
+
+ ctlp = device_get_softc(dev);
+
+ rp_pcireleaseresource(ctlp);
+
+ return (0);
+}
+#endif /* notdef */
+
+static void
+rp_pcireleaseresource(CONTROLLER_t *ctlp)
+{
+ rp_releaseresource(ctlp);
+
+ if (ctlp->io != NULL) {
+ if (ctlp->io[0] != NULL)
+ bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[0], ctlp->io[0]);
+ free(ctlp->io, M_DEVBUF);
+ }
+ if (ctlp->io_rid != NULL)
+ free(ctlp->io_rid, M_DEVBUF);
+}
+
+static int
+sPCIInitController( CONTROLLER_t *CtlP,
+ int AiopNum,
+ int IRQNum,
+ Byte_t Frequency,
+ int PeriodicOnly,
+ int VendorDevice)
+{
+ int i;
+
+ CtlP->CtlID = CTLID_0001; /* controller release 1 */
+
+ sPCIControllerEOI(CtlP);
+
+ /* Init AIOPs */
+ CtlP->NumAiop = 0;
+ for(i=0; i < AiopNum; i++)
+ {
+ /*device_printf(CtlP->dev, "aiop %d.\n", i);*/
+ CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */
+ /*device_printf(CtlP->dev, "ID = %d.\n", CtlP->AiopID[i]);*/
+ if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
+ {
+ break; /* done looking for AIOPs */
+ }
+
+ switch( VendorDevice ) {
+ case RP_DEVICE_ID_4Q:
+ case RP_DEVICE_ID_4J:
+ case RP_DEVICE_ID_4M:
+ CtlP->AiopNumChan[i] = 4;
+ break;
+ case RP_DEVICE_ID_6M:
+ CtlP->AiopNumChan[i] = 6;
+ break;
+ case RP_DEVICE_ID_8O:
+ case RP_DEVICE_ID_8J:
+ case RP_DEVICE_ID_8I:
+ case RP_DEVICE_ID_16I:
+ case RP_DEVICE_ID_32I:
+ CtlP->AiopNumChan[i] = 8;
+ break;
+ default:
+#if notdef
+ CtlP->AiopNumChan[i] = 8;
+#else
+ CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i);
+#endif /* notdef */
+ break;
+ }
+ /*device_printf(CtlP->dev, "%d channels.\n", CtlP->AiopNumChan[i]);*/
+ rp_writeaiop2(CtlP, i, _INDX_ADDR,_CLK_PRE); /* clock prescaler */
+ /*device_printf(CtlP->dev, "configuring clock prescaler.\n");*/
+ rp_writeaiop1(CtlP, i, _INDX_DATA,CLOCK_PRESC);
+ /*device_printf(CtlP->dev, "configured clock prescaler.\n");*/
+ CtlP->NumAiop++; /* bump count of AIOPs */
+ }
+
+ if(CtlP->NumAiop == 0)
+ return(-1);
+ else
+ return(CtlP->NumAiop);
+}
+
+/*
+ * ARGSUSED
+ * Maps (aiop, offset) to rid.
+ */
+static int
+rp_pci_aiop2rid(int aiop, int offset)
+{
+ /* Always return zero for a PCI controller. */
+ return 0;
+}
+
+/*
+ * ARGSUSED
+ * Maps (aiop, offset) to the offset of resource.
+ */
+static int
+rp_pci_aiop2off(int aiop, int offset)
+{
+ /* Each AIOP reserves 0x40 bytes. */
+ return aiop * 0x40 + offset;
+}
+
+/* Read the int status for a PCI controller. */
+static unsigned char
+rp_pci_ctlmask(CONTROLLER_t *ctlp)
+{
+ return sPCIGetControllerIntStatus(ctlp);
+}
+
+static device_method_t rp_pcimethods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rp_pciprobe),
+ DEVMETHOD(device_attach, rp_pciattach),
+#if notdef
+ DEVMETHOD(device_detach, rp_pcidetach),
+ DEVMETHOD(device_shutdown, rp_pcishutdown),
+#endif /* notdef */
+
+ { 0, 0 }
+};
+
+static driver_t rp_pcidriver = {
+ "rp",
+ rp_pcimethods,
+ sizeof(CONTROLLER_t),
+};
+
+/*
+ * rp can be attached to a pci bus.
+ */
+DRIVER_MODULE(rp, pci, rp_pcidriver, rp_devclass, 0, 0);
diff --git a/sys/dev/rp/rpreg.h b/sys/dev/rp/rpreg.h
new file mode 100644
index 0000000..a7cde1b
--- /dev/null
+++ b/sys/dev/rp/rpreg.h
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (c) Comtrol Corporation <support@comtrol.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted prodived that the follwoing conditions
+ * are met.
+ * 1. Redistributions of source code must retain the above copyright
+ * notive, this list of conditions and the following disclainer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials prodided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Comtrol Corporation.
+ * 4. The name of Comtrol Corporation may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Begin OS-specific defines - rpreg.h - for RocketPort FreeBSD
+ */
+
+typedef unsigned char Byte_t;
+typedef unsigned int ByteIO_t;
+
+typedef unsigned int Word_t;
+typedef unsigned int WordIO_t;
+
+typedef unsigned long DWord_t;
+typedef unsigned int DWordIO_t;
+
+#define rp_readio(size, ctlp, rid, offset) \
+ (bus_space_read_##size(rman_get_bustag(ctlp->io[rid]), rman_get_bushandle(ctlp->io[rid]), offset))
+#define rp_readmultiio(size, ctlp, rid, offset, addr, count) \
+ (bus_space_read_multi_##size(rman_get_bustag(ctlp->io[rid]), rman_get_bushandle(ctlp->io[rid]), offset, addr, count))
+#define rp_writeio(size, ctlp, rid, offset, data) \
+ (bus_space_write_##size(rman_get_bustag(ctlp->io[rid]), rman_get_bushandle(ctlp->io[rid]), offset, data))
+#define rp_writemultiio(size, ctlp, rid, offset, addr, count) \
+ (bus_space_write_multi_##size(rman_get_bustag(ctlp->io[rid]), rman_get_bushandle(ctlp->io[rid]), offset, addr, count))
+
+#define rp_readio1(ctlp, rid, offset) rp_readio(1, ctlp, rid, offset)
+#define rp_readio2(ctlp, rid, offset) rp_readio(2, ctlp, rid, offset)
+#define rp_readio4(ctlp, rid, offset) rp_readio(4, ctlp, rid, offset)
+#define rp_writeio1(ctlp, rid, offset, data) rp_writeio(1, ctlp, rid, offset, data)
+#define rp_writeio2(ctlp, rid, offset, data) rp_writeio(2, ctlp, rid, offset, data)
+#define rp_writeio4(ctlp, rid, offset, data) rp_writeio(4, ctlp, rid, offset, data)
+#define rp_readmultiio1(ctlp, rid, offset, addr, count) rp_readmultiio(1, ctlp, rid, offset, addr, count)
+#define rp_readmultiio2(ctlp, rid, offset, addr, count) rp_readmultiio(2, ctlp, rid, offset, addr, count)
+#define rp_readmultiio4(ctlp, rid, offset, addr, count) rp_readmultiio(4, ctlp, rid, offset, addr, count)
+#define rp_writemultiio1(ctlp, rid, offset, addr, count) rp_writemultiio(1, ctlp, rid, offset, addr, count)
+#define rp_writemultiio2(ctlp, rid, offset, addr, count) rp_writemultiio(2, ctlp, rid, offset, addr, count)
+#define rp_writemultiio4(ctlp, rid, offset, addr, count) rp_writemultiio(4, ctlp, rid, offset, addr, count)
+
+#define rp_readaiop1(ctlp, aiop, offset) \
+ (rp_readio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset)))
+#define rp_readaiop2(ctlp, aiop, offset) \
+ (rp_readio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset)))
+#define rp_readaiop4(ctlp, aiop, offset) \
+ (rp_readio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset)))
+#define rp_readmultiaiop1(ctlp, aiop, offset, addr, count) \
+ (rp_readmultiio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+#define rp_readmultiaiop2(ctlp, aiop, offset, addr, count) \
+ (rp_readmultiio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+#define rp_readmultiaiop4(ctlp, aiop, offset, addr, count) \
+ (rp_readmultiio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+#define rp_writeaiop1(ctlp, aiop, offset, data) \
+ (rp_writeio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data))
+#define rp_writeaiop2(ctlp, aiop, offset, data) \
+ (rp_writeio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data))
+#define rp_writeaiop4(ctlp, aiop, offset, data) \
+ (rp_writeio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data))
+#define rp_writemultiaiop1(ctlp, aiop, offset, addr, count) \
+ (rp_writemultiio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+#define rp_writemultiaiop2(ctlp, aiop, offset, addr, count) \
+ (rp_writemultiio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+#define rp_writemultiaiop4(ctlp, aiop, offset, addr, count) \
+ (rp_writemultiio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count))
+
+#define rp_readch1(chp, offset) \
+ (rp_readaiop1((chp)->CtlP, (chp)->AiopNum, offset))
+#define rp_readch2(chp, offset) \
+ (rp_readaiop2((chp)->CtlP, (chp)->AiopNum, offset))
+#define rp_readch4(chp, offset) \
+ (rp_readaiop4((chp)->CtlP, (chp)->AiopNum, offset))
+#define rp_readmultich1(chp, offset, addr, count) \
+ (rp_readmultiaiop1((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+#define rp_readmultich2(chp, offset, addr, count) \
+ (rp_readmultiaiop2((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+#define rp_readmultich4(chp, offset, addr, count) \
+ (rp_readmultiaiop4((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+#define rp_writech1(chp, offset, data) \
+ (rp_writeaiop1((chp)->CtlP, (chp)->AiopNum, offset, data))
+#define rp_writech2(chp, offset, data) \
+ (rp_writeaiop2((chp)->CtlP, (chp)->AiopNum, offset, data))
+#define rp_writech4(chp, offset, data) \
+ (rp_writeaiop4((chp)->CtlP, (chp)->AiopNum, offset, data))
+#define rp_writemultich1(chp, offset, addr, count) \
+ (rp_writemultiaiop1((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+#define rp_writemultich2(chp, offset, addr, count) \
+ (rp_writemultiaiop2((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+#define rp_writemultich4(chp, offset, addr, count) \
+ (rp_writemultiaiop4((chp)->CtlP, (chp)->AiopNum, offset, addr, count))
+
+/*
+ * End of OS-specific defines
+ */
+
+#define ROCKET_H
+
+#define CTL_SIZE 4
+#define AIOP_CTL_SIZE 4
+#define CHAN_AIOP_SIZE 8
+#define MAX_PORTS_PER_AIOP 8
+#define MAX_AIOPS_PER_BOARD 4
+#define MAX_PORTS_PER_BOARD 32
+
+/* Controller ID numbers */
+#define CTLID_NULL -1 /* no controller exists */
+#define CTLID_0001 0x0001 /* controller release 1 */
+
+/* AIOP ID numbers, identifies AIOP type implementing channel */
+#define AIOPID_NULL -1 /* no AIOP or channel exists */
+#define AIOPID_0001 0x0001 /* AIOP release 1 */
+
+#define NULLDEV -1 /* identifies non-existant device */
+#define NULLCTL -1 /* identifies non-existant controller */
+#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */
+#define NULLAIOP -1 /* identifies non-existant AIOP */
+#define NULLCHAN -1 /* identifies non-existant channel */
+
+/************************************************************************
+ Global Register Offsets - Direct Access - Fixed values
+************************************************************************/
+
+#define _CMD_REG 0x38 /* Command Register 8 Write */
+#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */
+#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */
+#define _UNUSED 0x3B /* Unused 8 */
+#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */
+#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */
+
+/************************************************************************
+ Channel Register Offsets for 1st channel in AIOP - Direct Access
+************************************************************************/
+#define _TD0 0x00 /* Transmit Data 16 Write */
+#define _RD0 0x00 /* Receive Data 16 Read */
+#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */
+#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */
+#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */
+
+/************************************************************************
+ Tx Control Register Offsets - Indexed - External - Fixed
+************************************************************************/
+#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */
+#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */
+#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */
+#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */
+#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */
+#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */
+
+/************************************************************************
+ Receive FIFO
+************************************************************************/
+#define RXFIFO_DATA 0x5f
+#define RXFIFO_OUT 0x5c
+#define RXFIFO_EN 0x08
+#define RXFIFO_DIS 0xa7
+
+/************************************************************************
+Memory Controller Register Offsets - Indexed - External - Fixed
+************************************************************************/
+#define _RX_FIFO 0x000 /* Rx FIFO */
+#define _TX_FIFO 0x800 /* Tx FIFO */
+#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */
+#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */
+#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */
+#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */
+#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */
+#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */
+
+#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */
+#define TXFIFO_SIZE 255 /* size of Tx FIFO */
+#define RXFIFO_SIZE 1023 /* size of Rx FIFO */
+
+/************************************************************************
+Tx Priority Buffer - Indexed - External - Fixed
+************************************************************************/
+#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */
+#define TXP_SIZE 0x20 /* 32 bytes */
+
+/************************************************************************
+Channel Register Offsets - Indexed - Internal - Fixed
+************************************************************************/
+
+#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */
+#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */
+#define _BAUD 0xFF4 /* Baud Rate 16 Write */
+#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */
+
+#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */
+
+#define BRD50 4607
+#define BRD75 3071
+#define BRD110 2094
+#define BRD134 1712
+#define BRD150 1535
+#define BRD200 1151
+#define BRD300 767
+#define BRD600 383
+#define BRD1200 191
+#define BRD1800 127
+#define BRD2000 114
+#define BRD2400 95
+#define BRD3600 64
+#define BRD4800 47
+#define BRD7200 31
+#define BRD9600 23
+#define BRD14400 15
+#define BRD19200 11
+#define BRD38400 5
+#define BRD57600 3
+#define BRD76800 2
+#define BRD115200 1
+#define BRD230400 0
+
+#define STMBREAK 0x08 /* BREAK */
+#define STMFRAME 0x04 /* framing error */
+#define STMRCVROVR 0x02 /* receiver over run error */
+#define STMPARITY 0x01 /* parity error */
+#define STMERROR (STMBREAK | STMFRAME | STMPARITY)
+#define STMBREAKH 0x800 /* BREAK */
+#define STMFRAMEH 0x400 /* framing error */
+#define STMRCVROVRH 0x200 /* receiver over run error */
+#define STMPARITYH 0x100 /* parity error */
+#define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH)
+
+#define CTS_ACT 0x20 /* CTS input asserted */
+#define DSR_ACT 0x10 /* DSR input asserted */
+#define CD_ACT 0x08 /* CD input asserted */
+#define TXFIFOMT 0x04 /* Tx FIFO is empty */
+#define TXSHRMT 0x02 /* Tx shift register is empty */
+#define RDA 0x01 /* Rx data available */
+#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */
+
+#define STATMODE 0x8000 /* status mode enable bit */
+#define RXFOVERFL 0x2000 /* receive FIFO overflow */
+#define RX2MATCH 0x1000 /* receive compare byte 2 match */
+#define RX1MATCH 0x0800 /* receive compare byte 1 match */
+#define RXBREAK 0x0400 /* received BREAK */
+#define RXFRAME 0x0200 /* received framing error */
+#define RXPARITY 0x0100 /* received parity error */
+#define STATERROR (RXBREAK | RXFRAME | RXPARITY)
+
+#define CTSFC_EN 0x80 /* CTS flow control enable bit */
+#define RTSTOG_EN 0x40 /* RTS toggle enable bit */
+#define TXINT_EN 0x10 /* transmit interrupt enable */
+#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */
+#define PARITY_EN 0x04 /* enable parity (0 = no parity) */
+#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */
+#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */
+
+#define SETBREAK 0x10 /* send break condition (must clear) */
+#define LOCALLOOP 0x08 /* local loopback set for test */
+#define SET_DTR 0x04 /* assert DTR */
+#define SET_RTS 0x02 /* assert RTS */
+#define TX_ENABLE 0x01 /* enable transmitter */
+
+#define RTSFC_EN 0x40 /* RTS flow control enable */
+#define RXPROC_EN 0x20 /* receive processor enable */
+#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */
+#define TRIG_1 0x08 /* trigger level 1 char */
+#define TRIG_1_2 0x10 /* trigger level 1/2 */
+#define TRIG_7_8 0x18 /* trigger level 7/8 */
+#define TRIG_MASK 0x18 /* trigger level mask */
+#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */
+#define RXINT_EN 0x02 /* Rx interrupt enable */
+#define MCINT_EN 0x01 /* modem change interrupt enable */
+
+#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */
+#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */
+#define SRC_INT 0x08 /* special receive condition interrupt */
+#define DELTA_CD 0x04 /* CD change interrupt */
+#define DELTA_CTS 0x02 /* CTS change interrupt */
+#define DELTA_DSR 0x01 /* DSR change interrupt */
+
+#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */
+#define IGN2_EN 0x08 /* ignore byte 2 enable */
+#define IGN1_EN 0x04 /* ignore byte 1 enable */
+#define COMP2_EN 0x02 /* compare byte 2 enable */
+#define COMP1_EN 0x01 /* compare byte 1 enable */
+
+#define RESET_ALL 0x80 /* reset AIOP (all channels) */
+#define TXOVERIDE 0x40 /* Transmit software off override */
+#define RESETUART 0x20 /* reset channel's UART */
+#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */
+#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */
+
+#define INTSTAT0 0x01 /* AIOP 0 interrupt status */
+#define INTSTAT1 0x02 /* AIOP 1 interrupt status */
+#define INTSTAT2 0x04 /* AIOP 2 interrupt status */
+#define INTSTAT3 0x08 /* AIOP 3 interrupt status */
+
+#define INTR_EN 0x08 /* allow interrupts to host */
+#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */
+
+#define CHAN3_EN 0x08 /* enable AIOP 3 */
+#define CHAN2_EN 0x04 /* enable AIOP 2 */
+#define CHAN1_EN 0x02 /* enable AIOP 1 */
+#define CHAN0_EN 0x01 /* enable AIOP 0 */
+#define FREQ_DIS 0x00
+#define FREQ_274HZ 0x60
+#define FREQ_137HZ 0x50
+#define FREQ_69HZ 0x40
+#define FREQ_34HZ 0x30
+#define FREQ_17HZ 0x20
+#define FREQ_9HZ 0x10
+#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */
+
+#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */
+
+#define RDATASIZE 72
+#define RREGDATASIZE 52
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct CONTROLLER_str;
+struct CHANNEL_str;
+
+/* The types of bus-specific methods */
+typedef int rp_aiop2rid_t(int, int);
+typedef int rp_aiop2off_t(int, int);
+typedef unsigned char rp_ctlmask_t(struct CONTROLLER_str *);
+
+/* Controller level information structure */
+struct CONTROLLER_str
+{
+ int CtlID;
+ int NumAiop;
+ int AiopID[AIOP_CTL_SIZE];
+ int AiopNumChan[AIOP_CTL_SIZE];
+
+ /* Device and resource management */
+ device_t dev; /* device */
+ int io_num; /* Number of IO resources */
+ int *io_rid; /* IO resource IDs */
+ struct resource **io; /* IO resources */
+
+ struct rp_port *rp; /* port */
+ struct tty *tty; /* tty */
+
+ /* Device nodes */
+ dev_t *dev_nodes;
+
+ /* Bus-specific properties */
+ void *bus_ctlp;
+
+ /* Bus-specific methods */
+ rp_aiop2rid_t *aiop2rid; /* (aiop, offset) -> rid */
+ rp_aiop2off_t *aiop2off; /* (aiop, offset) -> off */
+ rp_ctlmask_t *ctlmask; /* Int status */
+};
+typedef struct CONTROLLER_str CONTROLLER_T;
+typedef CONTROLLER_T CONTROLLER_t;
+
+/* Channel level information structure */
+struct CHANNEL_str
+{
+ CONTROLLER_t *CtlP;
+ int AiopNum;
+ int ChanID;
+ int ChanNum;
+
+ Word_t TxFIFO;
+ Word_t TxFIFOPtrs;
+ Word_t RxFIFO;
+ Word_t RxFIFOPtrs;
+ Word_t TxPrioCnt;
+ Word_t TxPrioPtr;
+ Word_t TxPrioBuf;
+
+ Byte_t R[RREGDATASIZE];
+
+ Byte_t BaudDiv[4];
+ Byte_t TxControl[4];
+ Byte_t RxControl[4];
+ Byte_t TxEnables[4];
+ Byte_t TxCompare[4];
+ Byte_t TxReplace1[4];
+ Byte_t TxReplace2[4];
+};
+
+typedef struct CHANNEL_str CHANNEL_T;
+typedef CHANNEL_T CHANNEL_t;
+typedef CHANNEL_T * CHANPTR_T;
+
+#define CHNOFF_TXRXDATA(chp) ((chp)->ChanNum * 2 + _TD0)
+#define CHNOFF_CHANSTAT(chp) ((chp)->ChanNum * 2 + _CHN_STAT0)
+#define CHNOFF_TXRXCOUNT(chp) ((chp)->ChanNum * 2 + _FIFO_CNT0)
+#define CHNOFF_INTID(chp) ((chp)->ChanNum + _INT_ID0)
+
+/***************************************************************************
+Function: sClrBreak
+Purpose: Stop sending a transmit BREAK signal
+Call: sClrBreak(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sClrBreak(ChP) \
+{ \
+ (ChP)->TxControl[3] &= ~SETBREAK; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sClrDTR
+Purpose: Clr the DTR output
+Call: sClrDTR(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sClrDTR(ChP) \
+{ \
+ (ChP)->TxControl[3] &= ~SET_DTR; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sClrRTS
+Purpose: Clr the RTS output
+Call: sClrRTS(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sClrRTS(ChP) \
+{ \
+ (ChP)->TxControl[3] &= ~SET_RTS; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sClrTxXOFF
+Purpose: Clear any existing transmit software flow control off condition
+Call: sClrTxXOFF(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sClrTxXOFF(ChP) \
+{ \
+ rp_writech1(ChP,_CMD_REG,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \
+ rp_writech1(ChP,_CMD_REG,(Byte_t)(ChP)->ChanNum); \
+}
+
+/***************************************************************************
+Function: sDisCTSFlowCtl
+Purpose: Disable output flow control using CTS
+Call: sDisCTSFlowCtl(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sDisCTSFlowCtl(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~CTSFC_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: DisParity
+Purpose: Disable parity
+Call: sDisParity(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: Function sSetParity() can be used in place of functions sEnParity(),
+ sDisParity(), sSetOddParity(), and sSetEvenParity().
+*/
+#define sDisParity(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~PARITY_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sDisRxFIFO
+Purpose: Disable Rx FIFO
+Call: sDisRxFIFO(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sDisRxFIFO(ChP) \
+{ \
+ (ChP)->R[0x32] = 0x0a; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->R[0x30]); \
+}
+
+/***************************************************************************
+Function: sDisRxStatusMode
+Purpose: Disable the Rx status mode
+Call: sDisRxStatusMode(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: This takes the channel out of the receive status mode. All
+ subsequent reads of receive data using sReadRxWord() will return
+ two data bytes.
+*/
+#define sDisRxStatusMode(ChP) rp_writech2(ChP,CHNOFF_CHANSTAT(ChP),0)
+
+/***************************************************************************
+Function: sDisTransmit
+Purpose: Disable transmit
+Call: sDisTransmit(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+ This disables movement of Tx data from the Tx FIFO into the 1 byte
+ Tx buffer. Therefore there could be up to a 2 byte latency
+ between the time sDisTransmit() is called and the transmit buffer
+ and transmit shift register going completely empty.
+*/
+#define sDisTransmit(ChP) \
+{ \
+ (ChP)->TxControl[3] &= ~TX_ENABLE; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sDisTxSoftFlowCtl
+Purpose: Disable Tx Software Flow Control
+Call: sDisTxSoftFlowCtl(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sDisTxSoftFlowCtl(ChP) \
+{ \
+ (ChP)->R[0x06] = 0x8a; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->R[0x04]); \
+}
+
+/***************************************************************************
+Function: sEnCTSFlowCtl
+Purpose: Enable output flow control using CTS
+Call: sEnCTSFlowCtl(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnCTSFlowCtl(ChP) \
+{ \
+ (ChP)->TxControl[2] |= CTSFC_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: EnParity
+Purpose: Enable parity
+Call: sEnParity(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: Function sSetParity() can be used in place of functions sEnParity(),
+ sDisParity(), sSetOddParity(), and sSetEvenParity().
+
+Warnings: Before enabling parity odd or even parity should be chosen using
+ functions sSetOddParity() or sSetEvenParity().
+*/
+#define sEnParity(ChP) \
+{ \
+ (ChP)->TxControl[2] |= PARITY_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sEnRTSFlowCtl
+Return: void
+*/
+#define sEnRTSFlowCtl(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~RTSTOG_EN; \
+ (ChP)->TxControl[3] &= ~SET_RTS; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+ (ChP)->RxControl[2] |= RTSFC_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->RxControl[0]); \
+}
+
+/***************************************************************************
+Function: sDisRTSFlowCtl
+Return: void
+*/
+#define sDisRTSFlowCtl(ChP) \
+{ \
+ (ChP)->RxControl[2] &= ~RTSFC_EN; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->RxControl[0]); \
+}
+
+/***************************************************************************
+Function: sEnRxFIFO
+Purpose: Enable Rx FIFO
+Call: sEnRxFIFO(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnRxFIFO(ChP) \
+{ \
+ (ChP)->R[0x32] = 0x08; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->R[0x30]); \
+}
+
+/***************************************************************************
+Function: sEnRxProcessor
+Purpose: Enable the receive processor
+Call: sEnRxProcessor(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: This function is used to start the receive processor. When
+ the channel is in the reset state the receive processor is not
+ running. This is done to prevent the receive processor from
+ executing invalid microcode instructions prior to the
+ downloading of the microcode.
+
+Warnings: This function must be called after valid microcode has been
+ downloaded to the AIOP, and it must not be called before the
+ microcode has been downloaded.
+*/
+#define sEnRxProcessor(ChP) \
+{ \
+ (ChP)->RxControl[2] |= RXPROC_EN; \
+ rp_writech2(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->RxControl[0]); \
+}
+
+/***************************************************************************
+Function: sEnRxStatusMode
+Purpose: Enable the Rx status mode
+Call: sEnRxStatusMode(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: This places the channel in the receive status mode. All subsequent
+ reads of receive data using sReadRxWord() will return a data byte
+ in the low word and a status byte in the high word.
+
+*/
+#define sEnRxStatusMode(ChP) rp_writech2(ChP,CHNOFF_CHANSTAT(ChP),STATMODE)
+
+/***************************************************************************
+Function: sEnTransmit
+Purpose: Enable transmit
+Call: sEnTransmit(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnTransmit(ChP) \
+{ \
+ (ChP)->TxControl[3] |= TX_ENABLE; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sGetAiopIntStatus
+Purpose: Get the AIOP interrupt status
+Call: sGetAiopIntStatus(CtlP,AiopNum)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int AiopNum; AIOP number
+Return: Byte_t: The AIOP interrupt status. Bits 0 through 7
+ represent channels 0 through 7 respectively. If a
+ bit is set that channel is interrupting.
+*/
+#define sGetAiopIntStatus(CtlP,AIOPNUM) rp_readaiop1(CtlP,AIOPNUM,_INT_CHAN)
+
+/***************************************************************************
+Function: sGetAiopNumChan
+Purpose: Get the number of channels supported by an AIOP
+Call: sGetAiopNumChan(CtlP,AiopNum)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int AiopNum; AIOP number
+Return: int: The number of channels supported by the AIOP
+*/
+#define sGetAiopNumChan(CtlP,AIOPNUM) CtlP->AiopNumChan[AIOPNUM]
+
+/***************************************************************************
+Function: sGetChanIntID
+Purpose: Get a channel's interrupt identification byte
+Call: sGetChanIntID(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: Byte_t: The channel interrupt ID. Can be any
+ combination of the following flags:
+ RXF_TRIG: Rx FIFO trigger level interrupt
+ TXFIFO_MT: Tx FIFO empty interrupt
+ SRC_INT: Special receive condition interrupt
+ DELTA_CD: CD change interrupt
+ DELTA_CTS: CTS change interrupt
+ DELTA_DSR: DSR change interrupt
+*/
+#define sGetChanIntID(ChP) (rp_readch1(ChP,(ChP)->ChanNum+_INT_ID0) & (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR))
+
+/***************************************************************************
+Function: sGetChanNum
+Purpose: Get the number of a channel within an AIOP
+Call: sGetChanNum(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: int: Channel number within AIOP, or NULLCHAN if channel does
+ not exist.
+*/
+#define sGetChanNum(ChP) (ChP)->ChanNum
+
+/***************************************************************************
+Function: sGetChanStatus
+Purpose: Get the channel status
+Call: sGetChanStatus(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: Word_t: The channel status. Can be any combination of
+ the following flags:
+ LOW BYTE FLAGS
+ CTS_ACT: CTS input asserted
+ DSR_ACT: DSR input asserted
+ CD_ACT: CD input asserted
+ TXFIFOMT: Tx FIFO is empty
+ TXSHRMT: Tx shift register is empty
+ RDA: Rx data available
+
+ HIGH BYTE FLAGS
+ STATMODE: status mode enable bit
+ RXFOVERFL: receive FIFO overflow
+ RX2MATCH: receive compare byte 2 match
+ RX1MATCH: receive compare byte 1 match
+ RXBREAK: received BREAK
+ RXFRAME: received framing error
+ RXPARITY: received parity error
+Warnings: This function will clear the high byte flags in the Channel
+ Status Register.
+*/
+#define sGetChanStatus(ChP) rp_readch2(ChP,CHNOFF_CHANSTAT(ChP))
+
+/***************************************************************************
+Function: sGetChanStatusLo
+Purpose: Get the low byte only of the channel status
+Call: sGetChanStatusLo(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: Byte_t: The channel status low byte. Can be any combination
+ of the following flags:
+ CTS_ACT: CTS input asserted
+ DSR_ACT: DSR input asserted
+ CD_ACT: CD input asserted
+ TXFIFOMT: Tx FIFO is empty
+ TXSHRMT: Tx shift register is empty
+ RDA: Rx data available
+*/
+#define sGetChanStatusLo(ChP) rp_readch1(ChP,CHNOFF_CHANSTAT(ChP))
+
+/***************************************************************************
+Function: sGetRxCnt
+Purpose: Get the number of data bytes in the Rx FIFO
+Call: sGetRxCnt(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: int: The number of data bytes in the Rx FIFO.
+Comments: Byte read of count register is required to obtain Rx count.
+
+*/
+#define sGetRxCnt(ChP) rp_readch2(ChP,CHNOFF_TXRXCOUNT(ChP))
+
+/***************************************************************************
+Function: sGetTxCnt
+Purpose: Get the number of data bytes in the Tx FIFO
+Call: sGetTxCnt(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: Byte_t: The number of data bytes in the Tx FIFO.
+Comments: Byte read of count register is required to obtain Tx count.
+
+*/
+#define sGetTxCnt(ChP) rp_readch1(ChP,CHNOFF_TXRXCOUNT(ChP))
+
+/*****************************************************************************
+Function: sGetTxRxDataIO
+Purpose: Get the offset of a channel's TxRx Data register
+Call: sGetTxRxDataIO(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Return: WordIO_t: offset of a channel's TxRx Data register
+*/
+#define sGetTxRxDataIO(ChP) CHNOFF_TXRXDATA(ChP)
+
+/***************************************************************************
+Function: sInitChanDefaults
+Purpose: Initialize a channel structure to its default state.
+Call: sInitChanDefaults(ChP)
+ CHANNEL_T *ChP; Ptr to the channel structure
+Comments: This function must be called once for every channel structure
+ that exists before any other SSCI calls can be made.
+
+*/
+#define sInitChanDefaults(ChP) \
+{ \
+ (ChP)->CtlP = NULLCTLPTR; \
+ (ChP)->AiopNum = NULLAIOP; \
+ (ChP)->ChanID = AIOPID_NULL; \
+ (ChP)->ChanNum = NULLCHAN; \
+}
+
+/***************************************************************************
+Function: sResetAiopByNum
+Purpose: Reset the AIOP by number
+Call: sResetAiopByNum(CTLP,AIOPNUM)
+ CONTROLLER_T CTLP; Ptr to controller structure
+ AIOPNUM; AIOP index
+*/
+#define sResetAiopByNum(CTLP,AIOPNUM) \
+{ \
+ rp_writeaiop1(CTLP,AIOPNUM,_CMD_REG,RESET_ALL); \
+ rp_writeaiop1(CTLP,AIOPNUM,_CMD_REG,0x0); \
+}
+
+/***************************************************************************
+Function: sSendBreak
+Purpose: Send a transmit BREAK signal
+Call: sSendBreak(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSendBreak(ChP) \
+{ \
+ (ChP)->TxControl[3] |= SETBREAK; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetBaud
+Purpose: Set baud rate
+Call: sSetBaud(ChP,Divisor)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Word_t Divisor; 16 bit baud rate divisor for channel
+*/
+#define sSetBaud(ChP,DIVISOR) \
+{ \
+ (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \
+ (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->BaudDiv[0]); \
+}
+
+/***************************************************************************
+Function: sSetData7
+Purpose: Set data bits to 7
+Call: sSetData7(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetData7(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~DATA8BIT; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetData8
+Purpose: Set data bits to 8
+Call: sSetData8(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetData8(ChP) \
+{ \
+ (ChP)->TxControl[2] |= DATA8BIT; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetDTR
+Purpose: Set the DTR output
+Call: sSetDTR(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetDTR(ChP) \
+{ \
+ (ChP)->TxControl[3] |= SET_DTR; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetEvenParity
+Purpose: Set even parity
+Call: sSetEvenParity(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: Function sSetParity() can be used in place of functions sEnParity(),
+ sDisParity(), sSetOddParity(), and sSetEvenParity().
+
+Warnings: This function has no effect unless parity is enabled with function
+ sEnParity().
+*/
+#define sSetEvenParity(ChP) \
+{ \
+ (ChP)->TxControl[2] |= EVEN_PAR; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetOddParity
+Purpose: Set odd parity
+Call: sSetOddParity(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: Function sSetParity() can be used in place of functions sEnParity(),
+ sDisParity(), sSetOddParity(), and sSetEvenParity().
+
+Warnings: This function has no effect unless parity is enabled with function
+ sEnParity().
+*/
+#define sSetOddParity(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~EVEN_PAR; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetRTS
+Purpose: Set the RTS output
+Call: sSetRTS(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetRTS(ChP) \
+{ \
+ (ChP)->TxControl[3] |= SET_RTS; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetRxTrigger
+Purpose: Set the Rx FIFO trigger level
+Call: sSetRxProcessor(ChP,Level)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Level; Number of characters in Rx FIFO at which the
+ interrupt will be generated. Can be any of the following flags:
+
+ TRIG_NO: no trigger
+ TRIG_1: 1 character in FIFO
+ TRIG_1_2: FIFO 1/2 full
+ TRIG_7_8: FIFO 7/8 full
+Comments: An interrupt will be generated when the trigger level is reached
+ only if function sEnInterrupt() has been called with flag
+ RXINT_EN set. The RXF_TRIG flag in the Interrupt Idenfification
+ register will be set whenever the trigger level is reached
+ regardless of the setting of RXINT_EN.
+
+*/
+#define sSetRxTrigger(ChP,LEVEL) \
+{ \
+ (ChP)->RxControl[2] &= ~TRIG_MASK; \
+ (ChP)->RxControl[2] |= LEVEL; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->RxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetStop1
+Purpose: Set stop bits to 1
+Call: sSetStop1(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetStop1(ChP) \
+{ \
+ (ChP)->TxControl[2] &= ~STOP2; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sSetStop2
+Purpose: Set stop bits to 2
+Call: sSetStop2(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sSetStop2(ChP) \
+{ \
+ (ChP)->TxControl[2] |= STOP2; \
+ rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->TxControl[0]); \
+}
+
+/***************************************************************************
+Function: sStartRxProcessor
+Purpose: Start a channel's receive processor
+Call: sStartRxProcessor(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+Comments: This function is used to start a Rx processor after it was
+ stopped with sStopRxProcessor() or sStopSWInFlowCtl(). It
+ will restart both the Rx processor and software input flow control.
+
+*/
+#define sStartRxProcessor(ChP) rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&(ChP)->R[0])
+
+/***************************************************************************
+Function: sWriteTxByte
+Purpose: Write a transmit data byte to a channel.
+ CHANNEL_T *ChP; Ptr to channel structure
+ ByteIO_t io: Channel transmit register I/O address. This can
+ be obtained with sGetTxRxDataIO().
+ Byte_t Data; The transmit data byte.
+Warnings: This function writes the data byte without checking to see if
+ sMaxTxSize is exceeded in the Tx FIFO.
+*/
+#define sWriteTxByte(ChP,IO,DATA) rp_writech1(ChP,IO,DATA)
+
+int sReadAiopID(CONTROLLER_T *CtlP, int aiop);
+int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop);
+int sInitChan( CONTROLLER_T *CtlP,
+ CHANNEL_T *ChP,
+ int AiopNum,
+ int ChanNum);
+Byte_t sGetRxErrStatus(CHANNEL_T *ChP);
+void sStopRxProcessor(CHANNEL_T *ChP);
+void sStopSWInFlowCtl(CHANNEL_T *ChP);
+void sFlushRxFIFO(CHANNEL_T *ChP);
+void sFlushTxFIFO(CHANNEL_T *ChP);
+int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data);
+void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags);
+void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags);
+int rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports);
+void rp_releaseresource(CONTROLLER_t *ctlp);
+
+#ifndef ROCKET_C
+extern Byte_t R[RDATASIZE];
+extern CONTROLLER_T sController[CTL_SIZE];
+extern Byte_t sIRQMap[16];
+#endif
+extern Byte_t rp_sBitMapClrTbl[8];
+extern Byte_t rp_sBitMapSetTbl[8];
diff --git a/sys/dev/rp/rpvar.h b/sys/dev/rp/rpvar.h
new file mode 100644
index 0000000..41aee02
--- /dev/null
+++ b/sys/dev/rp/rpvar.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) Comtrol Corporation <support@comtrol.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted prodived that the follwoing conditions
+ * are met.
+ * 1. Redistributions of source code must retain the above copyright
+ * notive, this list of conditions and the following disclainer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials prodided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Comtrol Corporation.
+ * 4. The name of Comtrol Corporation may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * rpvar.h --- RocketPort data structure includes for FreeBSD
+ */
+
+#define RP_UNIT(x) dv_unit(x)
+#define RP_PORT(x) (minor(x) & 0x3f)
+#define MAX_RP_PORTS 128
+
+
+struct rp_port {
+ struct tty * rp_tty; /* cross reference */
+
+/* Initial state */
+ struct termios it_in;
+ struct termios it_out;
+
+/* Lock state */
+ struct termios lt_in;
+ struct termios lt_out;
+
+/* Nonzero if callout device is open */
+ unsigned char active_out;
+ unsigned char state; /* state of dtr */
+
+/* Time to hold DTR down on close */
+ int dtr_wait;
+ int wopeners; /* processes waiting for DCD */
+
+ int rp_port;
+ int rp_flags;
+ int rp_unit:2;
+ int rp_aiop:2;
+ int rp_chan:3;
+ int rp_intmask;
+ int rp_imask; /* Input mask */
+ int rp_fifo_lw;
+ int rp_restart;
+ int rp_overflows;
+ int rp_rts_iflow:1;
+ int rp_disable_writes:1;
+ int rp_cts:1;
+ int rp_waiting:1;
+ int rp_xmit_stopped:1;
+ CONTROLLER_t * rp_ctlp;
+ CHANNEL_t rp_channel;
+ unsigned short TxBuf[TXFIFO_SIZE/2 +1];
+ unsigned short RxBuf[RXFIFO_SIZE/2 +1];
+};
+
+/* Actually not used */
+#if notdef
+extern struct termios deftermios;
+#endif /* notdef */
OpenPOWER on IntegriCloud