Hi,

The following diff contains a port of the FreeBSD driver for RocketPort PCI
cards.  The tty interface works with getty(8) and the cua part with cu for
outbound connections.  Some issues are still in, which I could not figure out
yet.  I worked on this driver for one and half year now, and think it ready to
get in.

I've done a lot of clean up of the original FreeBSD code.  Because there is no
specification available, I kept most of the comments.  I also switched the
original polling mode, which is used in the FreeBSD and Linux version of the
driver to an interrupt driven mode.

This is my first major work in the driver section.  I'm sure that I may miss
something.  So, even nitpicks are welcome :-)

OK?

Thanks,
Jan

Index: share/man/man4/rp.4
===================================================================
RCS file: share/man/man4/rp.4
diff -N share/man/man4/rp.4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ share/man/man4/rp.4 2 Oct 2020 17:50:01 -0000
@@ -0,0 +1,54 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2020 Jan Klemkow <j.klem...@wemelug.de>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: October 3 2020 $
+.Dt RP 4
+.Os
+.Sh NAME
+.Nm rp
+.Nd Comtrol RocketPort Intelligent Serial Port Cards device driver
+.Sh SYNOPSIS
+.Cd "rp* at pci?"
+.Sh DESCRIPTION
+This driver provides an interface to RocketPort multiport serial boards.
+.Pp
+The device minor numbers for this driver are encoded as follows:
+.Bd -literal
+    d c c u u u u u    - bits in the minor device number
+
+    bits    meaning
+    ----    -------
+    uuuuu   physical serial line (i.e., unit) to use
+               0-7 on a 8Y, 0-15 on a 16Y
+
+    cc      card number
+
+    d       dial-out flag
+.Ed
+.Sh SEE ALSO
+.Xr com 4 ,
+.Xr cy 4 ,
+.Xr intro 4 ,
+.Xr pci 4 ,
+.Xr termios 4 ,
+.Xr tty 4
+.Sh AUTHORS
+This driver was written under contract for Comtrol Corporation by
+.An Theodore Ts'o Aq Mt ty...@mit.edu .
+It was ported to OpenBSD by
+.An Jan Klemkow Aq Mt j.klem...@wemelug.de .
+.Sh BUGS
+Modem control does not work properly.
Index: sys/arch/amd64/amd64/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/conf.c,v
retrieving revision 1.71
diff -u -p -r1.71 conf.c
--- sys/arch/amd64/amd64/conf.c 6 Jul 2020 04:32:25 -0000       1.71
+++ sys/arch/amd64/amd64/conf.c 2 Oct 2020 17:08:36 -0000
@@ -75,6 +75,12 @@ struct bdevsw        bdevsw[] =
 };
 int    nblkdev = nitems(bdevsw);
 
+/* open, close, read, write, ioctl, tty, mmap */
+#define cdev_pc_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \
+       dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), D_TTY }
+
 /* open, close, read, ioctl */
 #define cdev_joy_init(c,n) { \
        dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
@@ -132,6 +138,8 @@ cdev_decl(lms);
 #include "opms.h"
 cdev_decl(pms);
 #endif
+#include "rp.h"
+cdev_decl(rp);
 #include "cy.h"
 cdev_decl(cy);
 #include "tun.h"
@@ -222,7 +230,7 @@ struct cdevsw       cdevsw[] =
        cdev_notdef(),                  /* 31 */
        cdev_notdef(),                  /* 32 */
        cdev_notdef(),                  /* 33 */
-       cdev_notdef(),                  /* 34 */
+       cdev_tty_init(NRP,rp),          /* 34: Comtrol RocketPort serial port */
        cdev_notdef(),                  /* 35: Microsoft mouse */
        cdev_notdef(),                  /* 36: Logitech mouse */
        cdev_notdef(),                  /* 37: Extended PS/2 mouse */
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.493
diff -u -p -r1.493 GENERIC
--- sys/arch/amd64/conf/GENERIC 15 Sep 2020 18:31:14 -0000      1.493
+++ sys/arch/amd64/conf/GENERIC 2 Oct 2020 17:08:39 -0000
@@ -399,6 +399,7 @@ com*        at puc?
 # options CY_HW_RTS
 #cy*   at pci?                         # PCI cyclom serial card
 #cz*   at pci?                         # Cyclades-Z multi-port serial boards
+rp*    at pci?                         # PCI RocketPort serial card
 
 lpt0   at isa? port 0x378 irq 7        # standard PC parallel ports
 #lpt1  at isa? port 0x278
Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.691
diff -u -p -r1.691 files
--- sys/conf/files      20 Jul 2020 00:15:59 -0000      1.691
+++ sys/conf/files      2 Oct 2020 17:08:36 -0000
@@ -334,6 +334,10 @@ file       dev/ic/pcf8584.c                pcfiic
 define ac97
 file   dev/ic/ac97.c                   ac97
 
+# Comtrol RocketPort multiport serial cards
+device rp: tty
+file   dev/ic/rp.c                     rp & (rp_pci)   needs-flag
+
 # Cyclades Cyclom multiport serial cards
 device cy: tty
 file   dev/ic/cy.c                     cy & (cy_isa | cy_pci)  needs-flag
Index: sys/dev/ic/rp.c
===================================================================
RCS file: sys/dev/ic/rp.c
diff -N sys/dev/ic/rp.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/dev/ic/rp.c     2 Oct 2020 17:08:39 -0000
@@ -0,0 +1,1294 @@
+/* $OpenBSD$ */
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) Comtrol Corporation <supp...@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>
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <machine/bus.h>
+
+#include <dev/ic/rpreg.h>
+
+#define DEVNAME(_s)    ((_s)->sc_dev.dv_xname)
+#define DEVCUA(x)      (minor(x) & 0x80)
+
+static const char RP_Version[] = "3.02";
+
+static uint8_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 uint8_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 */
+uint8_t sIRQMap[16] =
+{
+   0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
+};
+#endif
+
+uint8_t rp_sBitMapClrTbl[8] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
+uint8_t rp_sBitMapSetTbl[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
+
+struct cfdriver rp_cd = {
+       NULL, "rp", DV_TTY
+};
+
+/*
+ * Read the AIOP idenfication number directly from an AIOP.
+ *
+ * Return:
+ * Flag AIOPID_XXXX if a valid AIOP is found, where X is replace by an
+ * identifying number.  Returns -1 if no valid AIOP is found.
+ *
+ * Warnings: No context switches are allowed while executing this function.
+ */
+int
+rp_read_aiopid(struct rp_softc *sc, int aiop)
+{
+       uint8_t AiopID; /* ID byte from AIOP */
+
+       rp_writeaiop1(sc, aiop, _CMD_REG, RESET_ALL);   /* reset AIOP */
+       rp_writeaiop1(sc, aiop, _CMD_REG, 0x0);
+       AiopID = rp_readaiop1(sc, aiop, _CHN_STAT0) & 0x07;
+
+       if (AiopID == 0x06)
+               return (1);
+
+       return (-1);    /* AIOP does not exist */
+}
+
+/*
+ * Read the number of channels available in an AIOP directly from an AIOP.
+ *
+ * Return: The number of channels available
+ *
+ * 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
+rp_read_aiop_numchan(struct rp_softc *sc, int aiop)
+{
+       uint16_t x, y;
+
+       /* write to chan 0 SRAM */
+       rp_writeaiop4(sc, aiop, _INDX_ADDR, 0x12340000L);
+
+       /* read from SRAM, chan 0 */
+       rp_writeaiop2(sc, aiop, _INDX_ADDR, 0);
+       x = rp_readaiop2(sc, aiop, _INDX_DATA);
+
+       /* read from SRAM, chan 4 */
+       rp_writeaiop2(sc, aiop, _INDX_ADDR, 0x4000);
+       y = rp_readaiop2(sc, aiop, _INDX_DATA);
+
+       if (x != y)     /* if different must be 8 chan */
+               return (8);
+
+       return (4);
+}
+
+/*
+ * Initialization of a channel and channel structure
+ *
+ * Return: True if initialization succeeded, false if it fails because channel
+ * number exceeds number of channels available in AIOP.
+ *
+ * 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
+rp_init_chan(struct rp_softc *sc, struct rp_chan *ch, int AiopNum, int ChanNum)
+{
+       int i, ChOff;
+       static uint8_t R[4];
+
+       if (ChanNum >= sc->AiopNumChan[AiopNum])
+               return (false); /* exceeds num chans in AIOP */
+
+       /* Channel, AIOP, and controller identifiers */
+       ch->sc = sc;
+       ch->ChanID = sc->AiopID[AiopNum];
+       ch->AiopNum = AiopNum;
+       ch->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(ch, _INDX_ADDR, lemtoh32(R));
+       }
+
+       for (i = 0; i < RREGDATASIZE; i += 4) {
+               ch->R[i] = RRegData[i];
+               ch->R[i+1] = RRegData[i+1] + 0x10 * ChanNum;
+               ch->R[i+2] = RRegData[i+2];
+               ch->R[i+3] = RRegData[i+3];
+       }
+
+       /* Indexed registers */
+       ChOff = (uint16_t)ChanNum * 0x1000;
+
+       ch->BaudDiv[0] = (uint8_t)(ChOff + _BAUD);
+       ch->BaudDiv[1] = (uint8_t)((ChOff + _BAUD) >> 8);
+       ch->BaudDiv[2] = (uint8_t)RP_BRD9600;
+       ch->BaudDiv[3] = (uint8_t)(RP_BRD9600 >> 8);
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->BaudDiv));
+
+       ch->TxControl[0] = (uint8_t)(ChOff + _TX_CTRL);
+       ch->TxControl[1] = (uint8_t)((ChOff + _TX_CTRL) >> 8);
+       ch->TxControl[2] = 0;
+       ch->TxControl[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxControl));
+
+       ch->RxControl[0] = (uint8_t)(ChOff + _RX_CTRL);
+       ch->RxControl[1] = (uint8_t)((ChOff + _RX_CTRL) >> 8);
+       ch->RxControl[2] = 0;
+       ch->RxControl[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->RxControl));
+
+       ch->TxEnables[0] = (uint8_t)(ChOff + _TX_ENBLS);
+       ch->TxEnables[1] = (uint8_t)((ChOff + _TX_ENBLS) >> 8);
+       ch->TxEnables[2] = 0;
+       ch->TxEnables[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxEnables));
+
+       ch->TxCompare[0] = (uint8_t)(ChOff + _TXCMP1);
+       ch->TxCompare[1] = (uint8_t)((ChOff + _TXCMP1) >> 8);
+       ch->TxCompare[2] = 0;
+       ch->TxCompare[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxCompare));
+
+       ch->TxReplace1[0] = (uint8_t)(ChOff + _TXREP1B1);
+       ch->TxReplace1[1] = (uint8_t)((ChOff + _TXREP1B1) >> 8);
+       ch->TxReplace1[2] = 0;
+       ch->TxReplace1[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxReplace1));
+
+       ch->TxReplace2[0] = (uint8_t)(ChOff + _TXREP2);
+       ch->TxReplace2[1] = (uint8_t)((ChOff + _TXREP2) >> 8);
+       ch->TxReplace2[2] = 0;
+       ch->TxReplace2[3] = 0;
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxReplace2));
+
+       ch->TxFIFOPtrs = ChOff + _TXF_OUTP;
+       ch->TxFIFO = ChOff + _TX_FIFO;
+
+       /* apply reset Tx FIFO count */
+       rp_writech1(ch, _CMD_REG, (uint8_t)ChanNum | RESTXFCNT);
+
+       rp_writech1(ch, _CMD_REG, (uint8_t)ChanNum);    /* remove reset Tx FIFO 
count */
+       rp_writech2(ch, _INDX_ADDR, ch->TxFIFOPtrs);    /* clear Tx in/out ptrs 
*/
+       rp_writech2(ch, _INDX_DATA, 0);
+       ch->RxFIFOPtrs = ChOff + _RXF_OUTP;
+       ch->RxFIFO = ChOff + _RX_FIFO;
+
+       /* apply reset Rx FIFO count */
+       rp_writech1(ch, _CMD_REG, (uint8_t)ChanNum | RESRXFCNT);
+
+       rp_writech1(ch, _CMD_REG, (uint8_t)ChanNum);    /* remove reset Rx FIFO 
count */
+       rp_writech2(ch, _INDX_ADDR, ch->RxFIFOPtrs);    /* clear Rx out ptr */
+       rp_writech2(ch, _INDX_DATA, 0);
+       rp_writech2(ch, _INDX_ADDR, ch->RxFIFOPtrs + 2);        /* clear Rx in 
ptr */
+       rp_writech2(ch, _INDX_DATA, 0);
+       ch->TxPrioCnt = ChOff + _TXP_CNT;
+       rp_writech2(ch, _INDX_ADDR, ch->TxPrioCnt);
+       rp_writech1(ch, _INDX_DATA, 0);
+       ch->TxPrioPtr = ChOff + _TXP_PNTR;
+       rp_writech2(ch, _INDX_ADDR, ch->TxPrioPtr);
+       rp_writech1(ch, _INDX_DATA, 0);
+       ch->TxPrioBuf = ChOff + _TXP_BUF;
+       rp_enable_rx_processor(ch);     /* start the rx processor */
+
+       return (true);
+}
+
+/*
+ * Stop the receive processor from processing a channel.
+ *
+ * The receive processor can be started again with rp_start_rx_processor().
+ * 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
+rp_stop_rx_processor(struct rp_chan *ch)
+{
+       uint8_t R[4];
+
+       R[0] = ch->R[0];
+       R[1] = ch->R[1];
+       R[2] = 0x0a;
+       R[3] = ch->R[3];
+
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(R));
+}
+
+/*
+ * 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
+rp_flush_rx_fifo(struct rp_chan *ch)
+{
+       int     RxFIFOEnabled = false;  /* true if Rx FIFO enabled */
+       uint8_t Ch;                     /* channel number within AIOP */
+
+       if (rp_get_rx_cnt(ch) == 0)     /* Rx FIFO empty */
+               return;                 /* don't need to flush */
+
+       if (ch->R[0x32] == 0x08) {      /* Rx FIFO is enabled */
+               RxFIFOEnabled = true;
+               rp_disable_rx_fifo(ch); /* disable it */
+               delay(2);       /* delay 2 uS to allow proc to disable FIFO */
+       }
+       rp_chan_status(ch);     /* clear any pending Rx errors in chan stat */
+       Ch = (uint8_t)ch->ChanNum;
+       rp_writech1(ch, _CMD_REG, Ch | RESRXFCNT);      /* apply reset Rx FIFO 
count */
+       rp_writech1(ch, _CMD_REG, Ch);                  /* remove reset Rx FIFO 
count */
+       rp_writech2(ch, _INDX_ADDR, ch->RxFIFOPtrs);    /* clear Rx out ptr */
+       rp_writech2(ch, _INDX_DATA, 0);
+       rp_writech2(ch, _INDX_ADDR, ch->RxFIFOPtrs + 2);/* clear Rx in ptr */
+       rp_writech2(ch, _INDX_DATA, 0);
+
+       if (RxFIFOEnabled)
+               rp_enable_rx_fifo(ch);
+}
+
+/*
+ * 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
+rp_flush_tx_fifo(struct rp_chan *ch)
+{
+       int     TxEnabled = false;      /* true if transmitter enabled */
+       uint8_t Ch;                     /* channel number within AIOP */
+
+       if (rp_get_tx_cnt(ch) == 0)     /* Tx FIFO empty */
+               return;                 /* don't need to flush */
+
+       if (ch->TxControl[3] & TX_ENABLE) {
+               TxEnabled = true;
+               rp_disable_transmit(ch);        /* disable transmitter */
+       }
+
+       rp_stop_rx_processor(ch);       /* stop Rx processor */
+       delay(4);                       /* delay 4 uS to allow proc to stop */
+       Ch = (uint8_t)ch->ChanNum;
+       rp_writech1(ch, _CMD_REG, Ch | RESTXFCNT);      /* apply reset Tx FIFO 
count */
+       rp_writech1(ch, _CMD_REG, Ch);                  /* remove reset Tx FIFO 
count */
+       rp_writech2(ch, _INDX_ADDR, ch->TxFIFOPtrs);    /* clear Tx in/out ptrs 
*/
+       rp_writech2(ch, _INDX_DATA, 0);
+
+       if (TxEnabled)
+               rp_enable_transmit(ch); /* enable transmitter */
+
+       rp_start_rx_processor(ch);      /* restart Rx processor */
+}
+
+/*
+ * Write a byte of priority transmit data to a channel.
+ *
+ * Returns 1 if the bytes is successfully written, otherwise 0.  The priority
+ * byte is transmitted before any data in the Tx FIFO.
+ *
+ * Warnings: No context switches are allowed while executing this function.
+ */
+int
+rp_write_tx_prio_byte(struct rp_chan *ch, uint8_t data)
+{
+       uint8_t DWBuf[4];               /* buffer for double word writes */
+
+       if (rp_get_tx_cnt(ch) > 1) {    /* write it to Tx priority buffer */
+               /* get priority buffer status */
+               rp_writech2(ch, _INDX_ADDR, ch->TxPrioCnt);
+
+               /* priority buffer busy */
+               if (rp_readch1(ch, _INDX_DATA) & PRI_PEND)
+                       return (0);             /* nothing sent */
+
+               htolem16(DWBuf, ch->TxPrioBuf);/* data byte address */
+
+               DWBuf[2] = data;                /* data byte value */
+               DWBuf[3] = 0;                   /* priority buffer pointer */
+               rp_writech4(ch, _INDX_ADDR, lemtoh32(DWBuf)); /* write it out */
+
+               htolem16(DWBuf, ch->TxPrioCnt); /* Tx priority count address */
+
+               DWBuf[2] = PRI_PEND + 1;        /* indicate 1 byte pending */
+               DWBuf[3] = 0;                   /* priority buffer pointer */
+               rp_writech4(ch, _INDX_ADDR, lemtoh32(DWBuf)); /* write it out */
+       } else {
+               /* write it to Tx FIFO */
+               rp_write_tx_byte(ch, rp_txrx_data_io(ch), data);
+       }
+
+       return (1);     /* 1 byte sent */
+}
+
+/*
+ * Enable one or more interrupts for a channel
+ *
+ * rp_enable_interrupts(ch, flags)
+ *     struct rp_chan *ch; Ptr to channel structure
+ *     uint16_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
+ *                         rp_rx_trigger())
+ *             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.
+ *
+ * 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 rp_disable_interrupts().
+ *
+ * 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
+rp_enable_interrupts(struct rp_chan *ch, uint16_t flags)
+{
+       ch->RxControl[2] |= ((uint8_t)flags & (RXINT_EN | SRCINT_EN | 
MCINT_EN));
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->RxControl));
+
+       ch->TxControl[2] |= ((uint8_t)flags & TXINT_EN);
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxControl));
+
+       if (flags & CHANINT_EN) {
+               uint8_t Mask;   /* Interrupt Mask Register */
+
+               Mask = rp_readch1(ch,_INT_MASK) | rp_sBitMapSetTbl[ch->ChanNum];
+               rp_writech1(ch, _INT_MASK, Mask);
+       }
+}
+
+/*
+ * Disable one or more interrupts for a channel
+ *
+ * rp_disable_interrupts(ch, flags)
+ *       struct rp_chan *ch; Ptr to channel structure
+ *       uint16_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
+ *                         rp_rx_trigger())
+ *             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.
+ *
+ * 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 rp_enable_interrupts().
+ *
+ * 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
+rp_disable_interrupts(struct rp_chan *ch, uint16_t flags)
+{
+       ch->RxControl[2] &=
+           ~((uint8_t)flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->RxControl));
+
+       ch->TxControl[2] &= ~((uint8_t)flags & TXINT_EN);
+       rp_writech4(ch, _INDX_ADDR, lemtoh32(ch->TxControl));
+
+       if (flags & CHANINT_EN) {       /* Interrupt Mask Register */
+               uint8_t mask = rp_readch1(ch,_INT_MASK) & 
rp_sBitMapClrTbl[ch->ChanNum];
+               rp_writech1(ch, _INT_MASK, mask);
+       }
+}
+
+/*
+ * Begin OS-specific driver code
+ */
+
+#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)
+
+/*
+ * The top-level routines begin here
+ */
+int    rpclose(dev_t dev, int, int, struct proc *);
+void   rphardclose(struct tty *, struct rp_port *);
+/* TODO: int   rpmodem(struct tty *, int, int); */
+int    rpparam(struct tty *, struct termios *);
+void   rpstart(struct tty *);
+struct tty *rptty(dev_t);
+int    rpioctl(dev_t dev, u_long , caddr_t, int, struct proc *);
+int    rpopen(dev_t dev, int, int, struct proc *);
+
+static void
+rp_do_receive(struct rp_port *rp, struct tty *tp, struct rp_chan *cp,
+    unsigned int ChanStatus)
+{
+       unsigned int CharNStat;
+       int ToRecv, ch, s;
+
+       ToRecv = rp_get_rx_cnt(cp);
+#ifdef RP_DEBUG2
+       printf("%s port %d receive: %d bytes\n", DEVNAME(rp->rp_sc),
+           RP_PORT(tp->t_dev), ToRecv);
+#endif
+       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;
+                       rp_enable_rx_status_mode(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.
+        */
+       s = spltty();
+       if (ChanStatus & STATMODE) {
+               while (ToRecv) {
+                       CharNStat = rp_readch2(cp, rp_txrx_data_io(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++;
+
+                               printf("%s port %d tty overrun\n",
+                                   DEVNAME(rp->rp_sc), RP_PORT(tp->t_dev));
+                       }
+
+                       (*linesw[tp->t_line].l_rint)(ch, tp);
+                       ToRecv--;
+               }
+
+               /* After emtying FIFO in status mode, turn off status mode */
+               if (rp_get_rx_cnt(cp) == 0)
+                       rp_dis_rx_status_mode(cp);
+       } else {
+               ToRecv = rp_get_rx_cnt(cp);
+               while (ToRecv) {
+                       ch = rp_readch1(cp, rp_txrx_data_io(cp));
+                       (*linesw[tp->t_line].l_rint)(ch & 0xff, tp);
+                       ToRecv--;
+               }
+       }
+       splx(s);
+}
+
+static void
+rp_handle_port(struct rp_port *rp)
+{
+       struct rp_chan  *cp;
+       struct tty      *tp;
+       unsigned int     IntMask;
+       unsigned int     ChanStatus;
+       unsigned int     oldcts;
+
+       if (rp == NULL)
+               return;
+
+       cp = &rp->rp_channel;
+       tp = rp->rp_tty;
+       IntMask = rp_chan_intr_id(cp);
+       IntMask = IntMask & rp->rp_intmask;
+       ChanStatus = rp_chan_status(cp);
+       if (IntMask & RXF_TRIG)
+               rp_do_receive(rp, tp, cp, ChanStatus);
+
+       if (IntMask & DELTA_CD) {
+               if (ChanStatus & CD_ACT) {
+                       (void)(*linesw[tp->t_line].l_modem)(tp, 1);
+               } else {
+                       (void)(*linesw[tp->t_line].l_modem)(tp, 0);
+               }
+       }
+
+       oldcts = rp->rp_cts;
+       rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
+       CLR(tp->t_state, TS_BUSY);      // XXX: not sure with this
+       if (oldcts != rp->rp_cts) {
+               CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+#ifdef RP_DEBUG
+               printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" 
: "off", rp->rp_port);
+#endif
+               (*linesw[tp->t_line].l_start)(tp);
+       }
+}
+
+void
+rp_poll(struct rp_port *rp)
+{
+       struct rp_softc *sc = rp->rp_sc;
+       struct tty      *tp = rp->rp_tty;
+       int              count;
+       unsigned char    AiopMask;
+
+       if (sc->ctlmask(sc) & (1 << rp->rp_aiop)) {
+               AiopMask = rp_aiop_intr_status(sc, rp->rp_aiop);
+               if (AiopMask & (1 << rp->rp_chan)) {
+                       rp_handle_port(rp);
+               }
+       }
+
+       count = rp_get_tx_cnt(&rp->rp_channel);
+       if (count > 0)
+               rpstart(tp);
+}
+
+int
+rp_attach(struct rp_softc *sc, int num_aiops, int num_ports)
+{
+       struct rp_port  *rp;
+       struct tty      *tp;
+       int              unit;
+       int              num_chan;
+       int              aiop, chan, port;
+       int              ChanStatus;
+       int              retval;
+
+       unit = sc->sc_dev.dv_unit;
+
+       printf(" rp%d (Version %s) %d ports\n", unit, RP_Version, num_ports);
+
+       sc->num_ports = num_ports;
+       sc->sc_rp = rp = mallocarray(num_ports, sizeof(*rp), M_DEVBUF, 
M_NOWAIT|M_ZERO);
+
+       if (rp == NULL) {
+               printf("%s port %d rp_attach: could not malloc\n", DEVNAME(sc),
+                   port);
+               retval = ENOMEM;
+               goto nogo;
+       }
+
+       port = 0;
+       for (aiop = 0; aiop < num_aiops; aiop++) {
+               num_chan = sc->AiopNumChan[aiop];
+               for (chan = 0; chan < num_chan; chan++, port++, rp++) {
+                       rp->rp_tty = tp = ttymalloc(0);
+                       tp->t_oproc = rpstart;
+                       tp->t_param = rpparam;
+
+                       rp->rp_port = port;
+                       rp->rp_sc = sc;
+                       rp->rp_unit = unit;
+                       rp->rp_chan = chan;
+                       rp->rp_aiop = aiop;
+
+                       rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
+                               DELTA_CD | DELTA_CTS | DELTA_DSR;
+#ifdef notdef
+                       ChanStatus = rp_chan_status(&rp->rp_channel);
+#endif /* notdef */
+                       if (rp_init_chan(sc, &rp->rp_channel, aiop, chan) == 0){
+                               printf("%s port %d init channel (%d, %d, %d) 
failed.\n",
+                                   DEVNAME(sc), port, unit, aiop, chan);
+                               retval = ENXIO;
+                               goto nogo;
+                       }
+                       ChanStatus = rp_chan_status(&rp->rp_channel);
+                       rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
+               }
+       }
+
+       mtx_init(&sc->hwmtx, IPL_TTY);
+       sc->hwmtx_init = 1;
+       return (0);
+ nogo:
+       rp_releaseresource(sc);
+       return (retval);
+}
+
+void
+rp_releaseresource(struct rp_softc *sc)
+{
+       if (sc->sc_rp != NULL) {
+               int i;
+
+               for (i = 0; i < sc->num_ports; i++) {
+                       struct rp_port *rp = sc->sc_rp + i;
+                       ttyfree(rp->rp_tty);
+               }
+               free(sc->sc_rp, M_DEVBUF, sizeof(*(sc->sc_rp)) * sc->num_ports);
+               sc->sc_rp = NULL;
+       }
+}
+
+int
+rp_intr(void *arg)
+{
+       struct rp_softc *sc = arg;
+       int i;
+
+       if (sc->sc_rp == NULL)
+               return 0;
+
+       for (i = 0; i < sc->num_ports; i++)
+               rp_poll(sc->sc_rp + i);
+
+#define _PCI_INT_FUNC  0x3A
+#define PCI_STROB      0x2000
+#define INTR_EN_PCI    0x0010
+
+       rp_writeio2(sc, 0, _PCI_INT_FUNC, PCI_STROB | INTR_EN_PCI);
+
+       return 1;
+}
+
+int
+rpopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+       int              card = RP_CARD(dev);
+       int              port = RP_PORT(dev);
+       struct rp_softc *sc;
+       struct rp_port  *rp;
+       struct tty      *tp;
+       int              flags = 0;
+       int              error = 0;
+       int              s;
+
+       if (card >= rp_cd.cd_ndevs || (sc = rp_cd.cd_devs[card]) == NULL)
+               return (ENXIO);
+
+#ifdef RP_DEBUG
+       printf("%s open port %d flag 0x%x mode 0x%x\n", DEVNAME(sc), port, flag,
+           mode);
+#endif
+
+       rp = &sc->sc_rp[port];
+
+       s = spltty();
+       if (rp->rp_tty == NULL)
+               rp->rp_tty = ttymalloc(0);
+       splx(s);
+
+       tp = rp->rp_tty;
+       tp->t_oproc = rpstart;
+       tp->t_param = rpparam;
+       tp->t_dev = dev;
+       if (!ISSET(tp->t_state, TS_ISOPEN)) {
+               SET(tp->t_state, TS_WOPEN);
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+
+               if (ISSET(rp->rp_swflags, TIOCFLAG_CLOCAL))
+                       SET(tp->t_termios.c_cflag, CLOCAL);
+
+               s = spltty();
+
+               rpparam(tp, &tp->t_termios);
+               ttsetwater(tp);
+
+               /* No carrier detect support. */
+               SET(tp->t_state, TS_CARR_ON);
+
+               /* XXX: this block may not be here?! */
+               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, 
lemtoh32(rp->rp_channel.TxControl));
+               rp_rx_trigger(&rp->rp_channel, TRIG_1);
+               rp_dis_rx_status_mode(&rp->rp_channel);
+               rp_flush_rx_fifo(&rp->rp_channel);
+               rp_flush_tx_fifo(&rp->rp_channel);
+
+               rp_enable_interrupts(&rp->rp_channel,
+                   (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
+               rp_rx_trigger(&rp->rp_channel, TRIG_1);
+
+               rp_dis_rx_status_mode(&rp->rp_channel);
+               rp_clr_tx_xoff(&rp->rp_channel);
+
+//             rp_disable_RTS_flowctl(&rp->rp_channel);
+//             rp_disable_CTS_flowctl(&rp->rp_channel);
+
+               rp_disable_tx_soft_flowctl(&rp->rp_channel);
+               rp_start_rx_processor(&rp->rp_channel);
+
+               rp_enable_rx_fifo(&rp->rp_channel);
+               rp_enable_transmit(&rp->rp_channel);
+
+//             rp_set_DTR(&rp->rp_channel);
+//             rp_set_RTS(&rp->rp_channel);
+       } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) {
+               return (EBUSY);
+       } else {
+               s = spltty();
+       }
+
+       if (DEVCUA(dev)) {
+               if (ISSET(tp->t_state, TS_ISOPEN)) {
+                       /* Ah, but someone already is dialed in... */
+                       splx(s);
+                       return (EBUSY);
+               }
+               rp->rp_cua = 1;
+       } else {
+               /* tty (not cua) device; wait for carrier if necessary. */
+               if (ISSET(flag, O_NONBLOCK)) {
+                       if (rp->rp_cua) {
+                               /* Opening TTY non-blocking... but the CUA is 
busy. */
+                               splx(s);
+                               return (EBUSY);
+                       }
+               } else {
+                       while (rp->rp_cua || (!ISSET(tp->t_cflag, CLOCAL) &&
+                           !ISSET(tp->t_state, TS_CARR_ON))) {
+
+                               SET(tp->t_state, TS_WOPEN);
+                               error = ttysleep(tp, &tp->t_rawq,
+                                   TTIPRI | PCATCH, ttopen);
+
+                               /*
+                                * If TS_WOPEN has been reset, that means the
+                                * cua device has been closed.
+                                * We don't want to fail in that case,
+                                * so just go around again.
+                                */
+                               if (error && ISSET(tp->t_state, TS_WOPEN)) {
+                                       CLR(tp->t_state, TS_WOPEN);
+                                       splx(s);
+                                       return (error);
+                               }
+                       }
+               }
+       }
+       splx(s);
+
+       return ((*linesw[tp->t_line].l_open)(dev, tp, p));
+}
+
+int
+rpclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+       int              card = RP_CARD(dev);
+       int              port = RP_PORT(dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       struct tty      *tp = rp->rp_tty;
+       int              s;
+
+#ifdef RP_DEBUG
+       printf("%s close port %d flag 0x%x mode 0x%x\n", DEVNAME(sc), port,
+           flag, mode);
+#endif
+
+       if (!ISSET(tp->t_state, TS_ISOPEN))
+               return (0);
+
+       (*linesw[tp->t_line].l_close)(tp, flag, p);
+
+       s = spltty();
+
+       if (!ISSET(tp->t_state, TS_WOPEN))
+               rphardclose(tp, rp);
+
+       CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+       rp->rp_cua = 0;
+       splx(s);
+       ttyclose(tp);
+
+       return (0);
+}
+
+void
+rphardclose(struct tty *tp, struct rp_port *rp)
+{
+       struct rp_chan  *cp = &rp->rp_channel;
+
+       rp_flush_rx_fifo(cp);
+       rp_flush_tx_fifo(cp);
+       rp_disable_transmit(cp);
+       rp_disable_interrupts(cp, 
TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
+       rp_disable_RTS_flowctl(cp);
+       rp_disable_CTS_flowctl(cp);
+       rp_disable_tx_soft_flowctl(cp);
+       rp_clr_tx_xoff(cp);
+
+#ifdef DJA
+       if (tp->t_cflag&HUPCL || !(tp->t_state & TS_ISOPEN) || !tp->t_actout)
+               rp_clr_DTR(cp);
+
+       if (ISCALLOUT(tp->t_dev))
+               rp_clr_DTR(cp);
+
+       tp->t_actout = false;
+       wakeup(&tp->t_actout);
+       wakeup(TSA_CARR_ON(tp));
+#endif /* DJA */
+}
+
+int
+rpread(dev_t dev, struct uio *uio, int flag)
+{
+       int              card = RP_CARD(dev);
+       int              port = RP_PORT(dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       struct tty      *tp = rp->rp_tty;
+
+#ifdef RP_DEBUG1
+       printf("%s read port %d uio %p flag 0x%x\n", DEVNAME(sc), port, uio,
+           flag);
+#endif
+
+       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+rpwrite(dev_t dev, struct uio *uio, int flag)
+{
+       int card = RP_CARD(dev);
+       int port = RP_PORT(dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port *rp = &sc->sc_rp[port];
+       struct tty *tp = rp->rp_tty;
+
+#ifdef RP_DEBUG1
+       printf("%s write port %d uio %p flag 0x%x\n", DEVNAME(sc), port, uio,
+           flag);
+#endif
+
+       return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+rptty(dev_t dev)
+{
+       int card = RP_CARD(dev);
+       int port = RP_PORT(dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port *rp = &sc->sc_rp[port];
+       struct tty *tp = rp->rp_tty;
+
+       return (tp);
+}
+
+int
+rpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       int              card = RP_CARD(dev);
+       int              port = RP_PORT(dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       struct rp_chan  *cp = &rp->rp_channel;
+       struct tty      *tp = rp->rp_tty;
+       int error;
+
+#ifdef RP_DEBUG1
+       printf("%s port %d ioctl cmd 0x%lx data %p flag 0x%x\n", DEVNAME(sc),
+           port, cmd, data, flag);
+#endif
+
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+       if (error >= 0)
+               return (error);
+
+       error = ttioctl(tp, cmd, data, flag, p);
+       if (error >= 0)
+               return (error);
+
+       switch (cmd) {
+       case TIOCSBRK:
+               cp->TxControl[3] |= ~SETBREAK;
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case TIOCCBRK:
+               cp->TxControl[3] &= ~SETBREAK;
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case TIOCSDTR:  /* DIR on */
+               cp->TxControl[3] |= SET_DTR;
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case TIOCCDTR:  /* DIR off */
+               cp->TxControl[3] &= ~SET_DTR;
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case TIOCMSET:  /* set new modem control line values */
+               cp->TxControl[3] &= ~SET_DTR;
+               cp->TxControl[3] &= ~SET_RTS;
+       case TIOCMBIS:  /* turn modem control bits on */
+               if (*(int*)data & TIOCM_DTR)
+                       cp->TxControl[3] |= SET_DTR;
+               if (*(int*)data & TIOCM_RTS)
+                       cp->TxControl[3] |= SET_RTS;
+
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case TIOCMBIC:  /* turn modem control bits off */
+               if (*(int*)data & TIOCM_DTR)
+                       cp->TxControl[3] &= ~SET_DTR;
+               if (*(int*)data & TIOCM_RTS)
+                       cp->TxControl[3] &= ~SET_RTS;
+
+               rp_writech4(cp, _INDX_ADDR, lemtoh32(cp->TxControl));
+               break;
+       case  TIOCMGET: /* get modem control/status line state */
+               return (ENOTTY);
+       case  TIOCGFLAGS:/* get flags */
+               *(int *)data = rp->rp_swflags;
+               break;
+       case  TIOCSFLAGS:/* set flags */
+               error = suser(p);
+               if (error)
+                       return (EPERM);
+               rp->rp_swflags = *(int *)data;
+               break;
+       default:
+               return (ENOTTY);
+       }
+
+       return (0);
+}
+#if 0
+int
+rpmodem(struct tty *tp, int sigon, int sigoff)
+{
+       struct rp_port  *rp;
+       int              i, j, k;
+
+       rp = tty_softc(tp);
+       if (sigon != 0 || sigoff != 0) {
+               i = j = 0;
+               if (sigon & SER_DTR)
+                       i = SET_DTR;
+               if (sigoff & SER_DTR)
+                       j = SET_DTR;
+               if (sigon & SER_RTS)
+                       i = SET_RTS;
+               if (sigoff & SER_RTS)
+                       j = SET_RTS;
+               rp->rp_channel.TxControl[3] &= ~i;
+               rp->rp_channel.TxControl[3] |= j;
+               rp_writech4(&rp->rp_channel,_INDX_ADDR,
+                       lemtoh32(rp->rp_channel.TxControl));
+       } else {
+               i = rp_chan_status_lo(&rp->rp_channel);
+               j = rp->rp_channel.TxControl[3];
+               k = 0;
+               if (j & SET_DTR)
+                       k |= SER_DTR;
+               if (j & SET_RTS)
+                       k |= SER_RTS;
+               if (i & CD_ACT)
+                       k |= SER_DCD;
+               if (i & DSR_ACT)
+                       k |= SER_DSR;
+               if (i & CTS_ACT)
+                       k |= SER_CTS;
+               return(k);
+       }
+       return (0);
+}
+#endif
+
+static struct {
+       int baud;
+       int conversion;
+} baud_table[] = {
+       {B0,      0},           {B50,    RP_BRD50},     {B75,     RP_BRD75},
+       {B110,    RP_BRD110},   {B134,   RP_BRD134},    {B150,    RP_BRD150},
+       {B200,    RP_BRD200},   {B300,   RP_BRD300},    {B600,    RP_BRD600},
+       {B1200,   RP_BRD1200},  {B1800,  RP_BRD1800},   {B2400,   RP_BRD2400},
+       {B4800,   RP_BRD4800},  {B9600,  RP_BRD9600},   {B19200,  RP_BRD19200},
+       {B38400,  RP_BRD38400}, {B7200,  RP_BRD7200},   {B14400,  RP_BRD14400},
+       {B57600,  RP_BRD57600}, {B76800, RP_BRD76800},  {B115200, RP_BRD115200},
+       {B230400, RP_BRD230400}, {-1, -1}
+};
+
+static int
+rp_convert_baud(int baud)
+{
+       int i;
+
+       for (i = 0; baud_table[i].baud >= 0; i++)
+               if (baud_table[i].baud == baud)
+                       break;
+
+       return (baud_table[i].conversion);
+}
+
+int
+rpstop(struct tty *tp, int flag)
+{
+       int              card = RP_CARD(tp->t_dev);
+       int              port = RP_PORT(tp->t_dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       int              s;
+
+#ifdef RP_DEBUG
+       printf("%s port %d stop tty %p flag 0x%x\n", DEVNAME(sc), port, tp,
+           flag);
+#endif
+
+       s = spltty();
+       if (ISSET(tp->t_state, TS_BUSY)) {
+               if (!ISSET(tp->t_state, TS_TTSTOP))
+                       SET(tp->t_state, TS_FLUSH);
+
+               SET(rp->rp_flags, RPF_STOP);
+       }
+       splx(s);
+
+       return (0);
+}
+
+int
+rpparam(struct tty *tp, struct termios *t)
+{
+       int              card = RP_CARD(tp->t_dev);
+       int              port = RP_PORT(tp->t_dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       struct rp_chan  *cp = &rp->rp_channel;
+       int              cflag = t->c_cflag;
+       int              iflag = t->c_iflag;
+       int              ospeed = rp_convert_baud(t->c_ispeed);
+
+#ifdef RP_DEBUG1
+       printf("%s port %d param tty %p\n", DEVNAME(sc), port, tp);
+#endif
+
+#ifdef RPCLOCAL
+       int devshift;
+       devshift = umynor / 32;
+       devshift = 1 << devshift;
+       if (devshift & RPCLOCAL)
+               cflag |= CLOCAL;
+#endif
+
+       if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+               return (EINVAL);
+
+       if (t->c_ospeed == 0) {
+               rp_clr_DTR(cp);
+               return (0);
+       }
+       rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
+
+       /* Set baud rate ----- we only pay attention to ispeed */
+       rp_set_DTR(cp);
+       rp_set_RTS(cp);
+       rp_set_baud(cp, ospeed);
+
+       if (cflag & CSTOPB)
+               rp_set_stop2(cp);
+       else
+               rp_set_stop1(cp);
+
+       if (cflag & PARENB) {
+               rp_enable_parity(cp);
+
+               if (cflag & PARODD)
+                       rp_set_odd_parity(cp);
+               else
+                       rp_set_even_parity(cp);
+       } else {
+               rp_disable_parity(cp);
+       }
+
+       if ((cflag & CSIZE) == CS8) {
+               rp_set_data8(cp);
+               rp->rp_imask = 0xFF;
+       } else {
+               rp_set_data7(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)
+               rp_enable_CTS_flowctl(cp);
+       else
+               rp_disable_CTS_flowctl(cp);
+
+       /* XXX: dead code: rp_rts_iflow is never used */
+       if (cflag & CRTS_IFLOW)
+               rp->rp_rts_iflow = 1;
+       else
+               rp->rp_rts_iflow = 0;
+
+       if (cflag & CRTS_IFLOW)
+               rp_enable_RTS_flowctl(cp);
+       else
+               rp_disable_RTS_flowctl(cp);
+
+       /* just to be sure */
+       rpstart(tp);
+       return (0);
+}
+
+void
+rpstart(struct tty *tp)
+{
+       int              card = RP_CARD(tp->t_dev);
+       int              port = RP_PORT(tp->t_dev);
+       struct rp_softc *sc = rp_cd.cd_devs[card];
+       struct rp_port  *rp = &sc->sc_rp[port];
+       struct rp_chan  *cp = &rp->rp_channel;
+       int              xmit_fifo_room;
+       int              s, i, count, wcount;
+
+#ifdef RP_DEBUG1
+       printf("%s port %d start, tty %p\n", DEVNAME(sc), port, tp);
+#endif
+
+       s = spltty();
+
+       if (ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY))
+               goto out;
+
+       ttwakeupwr(tp);
+
+       if (tp->t_outq.c_cc == 0)
+               goto out;
+       SET(tp->t_state, TS_BUSY);
+
+       xmit_fifo_room = TXFIFO_SIZE - rp_get_tx_cnt(cp);
+       count = q_to_b(&tp->t_outq, rp->TxBuf, xmit_fifo_room);
+       if (xmit_fifo_room > 0) {
+               for (i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount--)
+                       rp_writech2(cp, rp_txrx_data_io(cp), 
lemtoh16(&rp->TxBuf[i]));
+
+               if (count & 1)
+                       rp_writech1(cp, rp_txrx_data_io(cp), 
rp->TxBuf[(count-1)]);
+       }
+
+ out:
+       splx(s);
+}
Index: sys/dev/ic/rpreg.h
===================================================================
RCS file: sys/dev/ic/rpreg.h
diff -N sys/dev/ic/rpreg.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/dev/ic/rpreg.h  2 Oct 2020 17:08:39 -0000
@@ -0,0 +1,805 @@
+/* $OpenBSD$ */
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) Comtrol Corporation <supp...@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.
+ *
+ */
+
+/*
+ * Begin OS-specific defines for RocketPort
+ */
+
+#define rp_readio(size, sc, rid, offset) \
+       (bus_space_read_##size((sc)->sc_iot, (sc)->sc_ioh, (offset)))
+#define rp_readmultiio(size, sc, rid, offset, addr, count) \
+       (bus_space_read_multi_##size((sc)->sc_iot, (sc)->sc_ioh, (offset), 
(addr), (count)))
+#define rp_writeio(size, sc, rid, offset, data) \
+       (bus_space_write_##size((sc)->sc_iot, (sc)->sc_ioh, (offset), (data)))
+#define rp_writemultiio(size, sc, rid, offset, addr, count) \
+       (bus_space_write_multi_##size((sc)->sc_iot, (sc)->sc_ioh, (offset), 
(addr), (count)))
+
+#define rp_readio1(sc, rid, offset) rp_readio(1, (sc), (rid), (offset))
+#define rp_readio2(sc, rid, offset) rp_readio(2, (sc), (rid), (offset))
+#define rp_readio4(sc, rid, offset) rp_readio(4, (sc), (rid), (offset))
+
+#define rp_writeio1(sc, rid, offset, data) \
+       rp_writeio(1, (sc), (rid), (offset), (data))
+#define rp_writeio2(sc, rid, offset, data) \
+       rp_writeio(2, (sc), (rid), (offset), (data))
+#define rp_writeio4(sc, rid, offset, data) \
+       rp_writeio(4, (sc), (rid), (offset), (data))
+
+#define rp_readmultiio1(sc, rid, offset, addr, count) \
+       rp_readmultiio(1, (sc), (rid), (offset), (addr), (count))
+#define rp_readmultiio2(sc, rid, offset, addr, count) \
+       rp_readmultiio(2, (sc), (rid), (offset), (addr), (count))
+#define rp_readmultiio4(sc, rid, offset, addr, count) \
+       rp_readmultiio(4, (sc), (rid), (offset), (addr), (count))
+
+#define rp_writemultiio1(sc, rid, offset, addr, count) \
+       rp_writemultiio(1, (sc), (rid), (offset), (addr), (count))
+#define rp_writemultiio2(sc, rid, offset, addr, count) \
+       rp_writemultiio(2, (sc), (rid), (offset), (addr), (count)) 
+#define rp_writemultiio4(sc, rid, offset, addr, count) \
+       rp_writemultiio(4, (sc), (rid), (offset), (addr), (count)) 
+
+#define rp_readaiop1(sc, aiop, offset) \
+       (rp_readio1((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset)))
+#define rp_readaiop2(sc, aiop, offset) \
+       (rp_readio2((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset)))
+#define rp_readaiop4(sc, aiop, offset) \
+       (rp_readio4((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset)))
+#define rp_readmultiaiop1(sc, aiop, offset, addr, count) \
+       (rp_readmultiio1((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+#define rp_readmultiaiop2(sc, aiop, offset, addr, count) \
+       (rp_readmultiio2((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+#define rp_readmultiaiop4(sc, aiop, offset, addr, count) \
+       (rp_readmultiio4((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+#define rp_writeaiop1(sc, aiop, offset, data) \
+       (rp_writeio1((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset), data))
+#define rp_writeaiop2(sc, aiop, offset, data) \
+       (rp_writeio2((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset), data))
+#define rp_writeaiop4(sc, aiop, offset, data) \
+       (rp_writeio4((sc), (sc)->aiop2rid(aiop, offset), (sc)->aiop2off(aiop, 
offset), data))
+#define rp_writemultiaiop1(sc, aiop, offset, addr, count) \
+       (rp_writemultiio1((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+#define rp_writemultiaiop2(sc, aiop, offset, addr, count) \
+       (rp_writemultiio2((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+#define rp_writemultiaiop4(sc, aiop, offset, addr, count) \
+       (rp_writemultiio4((sc), (sc)->aiop2rid(aiop, offset), 
(sc)->aiop2off(aiop, offset), addr, count))
+
+#define rp_readch1(ch, offset) \
+       (rp_readaiop1((ch)->sc, (ch)->AiopNum, offset))
+#define rp_readch2(ch, offset) \
+       (rp_readaiop2((ch)->sc, (ch)->AiopNum, offset))
+#define rp_readch4(ch, offset) \
+       (rp_readaiop4((ch)->sc, (ch)->AiopNum, offset))
+#define rp_readmultich1(ch, offset, addr, count) \
+       (rp_readmultiaiop1((ch)->sc, (ch)->AiopNum, offset, addr, count))
+#define rp_readmultich2(ch, offset, addr, count) \
+       (rp_readmultiaiop2((ch)->sc, (ch)->AiopNum, offset, addr, count))
+#define rp_readmultich4(ch, offset, addr, count) \
+       (rp_readmultiaiop4((ch)->sc, (ch)->AiopNum, offset, addr, count))
+#define rp_writech1(ch, offset, data) \
+       (rp_writeaiop1((ch)->sc, (ch)->AiopNum, offset, data))
+#define rp_writech2(ch, offset, data) \
+       (rp_writeaiop2((ch)->sc, (ch)->AiopNum, offset, data))
+#define rp_writech4(ch, offset, data) \
+       (rp_writeaiop4((ch)->sc, (ch)->AiopNum, offset, data))
+#define rp_writemultich1(ch, offset, addr, count) \
+       (rp_writemultiaiop1((ch)->sc, (ch)->AiopNum, offset, addr, count))
+#define rp_writemultich2(ch, offset, addr, count) \
+       (rp_writemultiaiop2((ch)->sc, (ch)->AiopNum, offset, addr, count))
+#define rp_writemultich4(ch, offset, addr, count) \
+       (rp_writemultiaiop4((ch)->sc, (ch)->AiopNum, offset, addr, count))
+
+/*
+ * Port number on card encoded in low 5 bits
+ * card number in next 2 bits (only space for 4 cards)
+ * high bit reserved for dialout flag
+ */
+#define RP_PORT(x) (minor(x) & 0xf)
+#define RP_CARD(x) ((minor(x) >> 5) & 3)
+
+/*
+ * End of OS-specific defines
+ */
+
+#define RP_CTL_SIZE             4
+#define RP_AIOP_CTL_SIZE        4
+#define RP_CHAN_AIOP_SIZE       8
+#define RP_MAX_PORTS_PER_AIOP   8
+#define RP_MAX_AIOPS_PER_BOARD  4
+#define RP_MAX_PORTS_PER_BOARD 32
+
+/* AIOP ID numbers, identifies AIOP type implementing channel */
+#define RP_AIOPID_NULL -1      /* no AIOP or channel exists */
+#define RP_AIOPID_0001 0x0001  /* AIOP release 1 */
+
+/*
+ * 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 RP_BRD50       4607
+#define RP_BRD75       3071
+#define RP_BRD110      2094
+#define RP_BRD134      1712
+#define RP_BRD150      1535
+#define RP_BRD200      1151
+#define RP_BRD300       767
+#define RP_BRD600       383
+#define RP_BRD1200      191
+#define RP_BRD1800      127
+#define RP_BRD2000      114
+#define RP_BRD2400       95
+#define RP_BRD3600       64
+#define RP_BRD4800       47
+#define RP_BRD7200       31
+#define RP_BRD9600       23
+#define RP_BRD14400      15
+#define RP_BRD19200      11
+#define RP_BRD38400       5
+#define RP_BRD57600       3
+#define RP_BRD76800       2
+#define RP_BRD115200      1
+#define RP_BRD230400      0
+
+#define STMPARITY      0x01    /* parity error */
+#define STMRCVROVR     0x02    /* receiver over run error */
+#define STMFRAME       0x04    /* framing error */
+#define STMBREAK       0x08    /* BREAK */
+#define STMERROR       (STMBREAK | STMFRAME | STMPARITY)
+#define STMPARITYH     0x100   /* parity error */
+#define STMRCVROVRH    0x200   /* receiver over run error */
+#define STMFRAMEH      0x400   /* framing error */
+#define STMBREAKH      0x800   /* BREAK */
+#define STMERRORH      (STMBREAKH | STMFRAMEH | STMPARITYH)
+
+#define RDA            0x01    /* Rx data available */
+#define TXSHRMT                0x02    /* Tx shift register is empty */
+#define TXFIFOMT       0x04    /* Tx FIFO is empty */
+#define CD_ACT         0x08    /* CD input asserted */
+#define DSR_ACT                0x10    /* DSR input asserted */
+#define CTS_ACT                0x20    /* CTS input asserted */
+#define DRAINED                (TXFIFOMT | TXSHRMT)    /* indicates Tx is 
drained */
+
+#define RXPARITY       0x0100  /* received parity error */
+#define RXFRAME                0x0200  /* received framing error */
+#define RXBREAK                0x0400  /* received BREAK */
+#define RX1MATCH       0x0800  /* receive compare byte 1 match */
+#define RX2MATCH       0x1000  /* receive compare byte 2 match */
+#define RXFOVERFL      0x2000  /* receive FIFO overflow */
+#define STATMODE       0x8000  /* status mode enable bit */
+#define STATERROR (RXBREAK | RXFRAME | RXPARITY)
+
+#define DATA8BIT       0x01    /* 8 bit data (0 = 7 bit data) */
+#define EVEN_PAR       0x02    /* even parity (0 = odd parity) */
+#define PARITY_EN      0x04    /* enable parity (0 = no parity) */
+#define STOP2          0x08    /* enable 2 stop bits (0 = 1 stop) */
+#define TXINT_EN       0x10    /* transmit interrupt enable */
+#define RTSTOG_EN      0x40    /* RTS toggle enable bit */
+#define CTSFC_EN       0x80    /* CTS flow control enable bit */
+
+#define TX_ENABLE      0x01    /* enable transmitter */
+#define SET_RTS                0x02    /* assert RTS */
+#define SET_DTR                0x04    /* assert DTR */
+#define LOCALLOOP      0x08    /* local loopback set for test */
+#define SETBREAK       0x10    /* send break condition (must clear) */
+
+#define TRIG_NO                0x00    /* Rx FIFO trigger level 0 (no trigger) 
*/
+#define MCINT_EN       0x01    /* modem change interrupt enable */
+#define RXINT_EN       0x02    /* Rx interrupt enable */
+#define SRCINT_EN      0x04    /* special Rx condition interrupt enable */
+#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 RXPROC_EN      0x20    /* receive processor enable */
+#define RTSFC_EN       0x40    /* RTS flow control enable */
+
+#define DELTA_DSR      0x01    /* DSR change interrupt */
+#define DELTA_CTS      0x02    /* CTS change interrupt */
+#define DELTA_CD       0x04    /* CD change interrupt */
+#define SRC_INT                0x08    /* special receive condition interrupt 
*/
+#define TXFIFO_MT      0x10    /* Tx FIFO empty interrupt */
+#define RXF_TRIG       0x20    /* Rx FIFO trigger level interrupt */
+
+#define COMP1_EN       0x01    /* compare byte 1 enable */
+#define COMP2_EN       0x02    /* compare byte 2 enable */
+#define IGN1_EN                0x04    /* ignore byte 1 enable */
+#define IGN2_EN                0x08    /* ignore byte 2 enable */
+#define REP1W2_EN      0x10    /* replace byte 1 with 2 bytes 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 CHAN0_EN       0x01    /* enable AIOP 0 */
+#define CHAN1_EN       0x02    /* enable AIOP 1 */
+#define CHAN2_EN       0x04    /* enable AIOP 2 */
+#define CHAN3_EN       0x08    /* enable AIOP 3 */
+
+#define FREQ_DIS       0x00
+#define FREQ_9HZ       0x10
+#define FREQ_17HZ      0x20
+#define FREQ_34HZ      0x30
+#define FREQ_69HZ      0x40
+#define FREQ_137HZ     0x50
+#define FREQ_274HZ     0x60
+#define PERIODIC_ONLY  0x80    /* only PERIODIC interrupt */
+
+#define CHANINT_EN     0x0100  /* flags to enable/disable channel ints */
+
+#define RDATASIZE      72
+#define RREGDATASIZE   52
+
+#define RP_PCI_BAR_1   PCI_MAPREG_START
+#define RP_PCI_BAR_2   PCI_MAPREG_START + 8
+
+struct rp_softc;
+struct rp_chan;
+
+/* 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 rp_softc *);
+
+/* Controller level information structure */
+struct rp_softc {
+       /* Device and resource management */
+       struct device   sc_dev;         /* device */
+
+       int             NumAiop;
+       int             AiopID[RP_AIOP_CTL_SIZE];
+       int             AiopNumChan[RP_AIOP_CTL_SIZE];
+
+        struct mutex   hwmtx;          /* Spinlock protecting hardware. */
+       int             hwmtx_init;
+       int             num_ports;
+
+       void                    *sc_ih;
+       bus_space_tag_t          sc_iot;
+       bus_space_handle_t       sc_ioh;
+       bus_size_t               sc_ios;
+
+       struct rp_port  *sc_rp;         /* port */
+       struct cdev    **dev_nodes;     /* Device nodes */
+       void            *bus_ctlp;      /* Bus-specific properties */
+
+       /* Bus-specific methods */
+       rp_aiop2rid_t   *aiop2rid;      /* (aiop, offset) -> rid */
+       rp_aiop2off_t   *aiop2off;      /* (aiop, offset) -> off */
+       rp_ctlmask_t    *ctlmask;       /* Int status */
+};
+
+/* Channel level information structure */
+struct rp_chan
+{
+       struct rp_softc *sc;
+       int              AiopNum;
+       int              ChanID;
+       int              ChanNum;
+
+       uint32_t         TxFIFO;
+       uint32_t         TxFIFOPtrs;
+       uint32_t         RxFIFO;
+       uint32_t         RxFIFOPtrs;
+       uint32_t         TxPrioCnt;
+       uint32_t         TxPrioPtr;
+       uint32_t         TxPrioBuf;
+
+       uint8_t          R[RREGDATASIZE];
+
+       uint8_t          BaudDiv[4];
+       uint8_t          TxControl[4];
+       uint8_t          RxControl[4];
+       uint8_t          TxEnables[4];
+       uint8_t          TxCompare[4];
+       uint8_t          TxReplace1[4];
+       uint8_t          TxReplace2[4];
+};
+
+#define CHNOFF_TXRXDATA(ch)    ((ch)->ChanNum * 2 + _TD0)
+#define CHNOFF_CHANSTAT(ch)    ((ch)->ChanNum * 2 + _CHN_STAT0)
+#define CHNOFF_TXRXCOUNT(ch)   ((ch)->ChanNum * 2 + _FIFO_CNT0)
+#define CHNOFF_INTID(ch)       ((ch)->ChanNum     + _INT_ID0)
+
+/* Clear the DTR output */
+#define rp_clr_DTR(ch) do {                                    \
+       (ch)->TxControl[3] &= ~SET_DTR;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/* Clear the RTS output */
+#define rp_clr_RTS(ch) do {                                    \
+       (ch)->TxControl[3] &= ~SET_RTS;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/* Clear any existing transmit software flow control off condition */
+#define rp_clr_tx_xoff(ch) do {                                                
\
+       rp_writech1(ch, _CMD_REG, TXOVERIDE | (uint8_t)(ch)->ChanNum);  \
+       rp_writech1(ch, _CMD_REG, (uint8_t)(ch)->ChanNum);              \
+} while (0)
+
+/* Disable output flow control using CTS */
+#define rp_disable_CTS_flowctl(ch) do {                                \
+       (ch)->TxControl[2] &= ~CTSFC_EN;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/*
+ * Function sSetParity() can be used in place of functions sEnParity(),
+ * sDisParity(), rp_set_odd_parity(), and sSetEvenParity().
+ */
+#define rp_disable_parity(ch) do {                             \
+       (ch)->TxControl[2] &= ~PARITY_EN;                       \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+#define rp_disable_rx_fifo(ch) do {                            \
+       (ch)->R[0x32] = 0x0a;                                   \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->R + 0x30));  \
+} while (0)
+
+/*
+ * This takes the channel out of the receive status mode.  All subsequent reads
+ * of receive data using sReadRxWord() will return two data bytes.
+ */
+#define rp_dis_rx_status_mode(ch) rp_writech2((ch), CHNOFF_CHANSTAT(ch), 0)
+
+/*
+ * 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
+ * rp_disable_transmit() is called and the transmit buffer and transmit shift
+ * register going completely empty.
+ */
+#define rp_disable_transmit(cp) do {                           \
+       (cp)->TxControl[3] &= ~TX_ENABLE;                       \
+       rp_writech4(cp, _INDX_ADDR, lemtoh32((cp)->TxControl)); \
+} while (0)
+
+#define rp_disable_tx_soft_flowctl(ch) do {                    \
+       (ch)->R[0x06] = 0x8a;                                   \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->R + 0x04));  \
+} while (0)
+
+/* enable output flow control using CTS */
+#define rp_enable_CTS_flowctl(ch) do {                         \
+       (ch)->TxControl[2] |= CTSFC_EN;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/*
+ * Function sSetParity() can be used in place of functions sEnParity(),
+ * sDisParity(), rp_set_odd_parity(), and sSetEvenParity().
+ *
+ * Warnings:
+ * Before enabling parity odd or even parity should be chosen using functions
+ * rp_set_odd_parity() or sSetEvenParity().
+ */
+#define rp_enable_parity(ch) do {                              \
+       (ch)->TxControl[2] |= PARITY_EN;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+#define rp_enable_RTS_flowctl(ch) do {                         \
+       (ch)->TxControl[2] &= ~RTSTOG_EN;                       \
+       (ch)->TxControl[3] &= ~SET_RTS;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+       (ch)->RxControl[2] |= RTSFC_EN;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->RxControl)); \
+} while (0)
+
+#define rp_disable_RTS_flowctl(ch) do {                                \
+       (ch)->RxControl[2] &= ~RTSFC_EN;                        \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->RxControl));\
+} while (0)
+
+#define rp_enable_rx_fifo(ch) do {                             \
+       (ch)->R[0x32] = 0x08;                                   \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->R + 0x30));  \
+} while (0)
+
+/*
+ * 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 rp_enable_rx_processor(ch) do {                                \
+       (ch)->RxControl[2] |= RXPROC_EN;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->RxControl)); \
+} while (0)
+
+/*
+ * 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 rp_enable_rx_status_mode(ch) \
+       rp_writech2(ch, CHNOFF_CHANSTAT(ch), STATMODE)
+
+#define rp_enable_transmit(ch) do {                            \
+       (ch)->TxControl[3] |= TX_ENABLE;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/*
+ * Purpose:  Get the AIOP interrupt status
+ *
+ * Returns the AIOP interrupt status.  Bits 0 through 7 represent channels 0
+ * through 7 respectively.  If a bit is set that channel is interrupting.
+ */
+#define rp_aiop_intr_status(sc, AIOPNUM) \
+       rp_readaiop1((sc), (AIOPNUM), _INT_CHAN)
+
+/*
+ * Get a channel's interrupt identification byte and returns 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 rp_chan_intr_id(ch)                                    \
+       (rp_readch1(ch, (ch)->ChanNum+_INT_ID0) &               \
+        (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR))
+
+/*
+ * Returns the channel status.  Can be any combination of the following flags:
+ *
+ * LOW BYTE FLAGS                      HIGH BYTE FLAGS
+ *
+ * CTS_ACT:  CTS input asserted                STATMODE:  status mode enable 
bit
+ * DSR_ACT:  DSR input asserted                RXFOVERFL: receive FIFO overflow
+ * D_ACT:    CD input asserted         RX2MATCH:  receive compare byte 2 match
+ * TXFIFOMT: Tx FIFO is empty          RX1MATCH:  receive compare byte 1 match
+ * TXSHRMT:  Tx shift reg. is empty    RXBREAK:   received BREAK
+ * RDA:             Rx data available          RXFRAME:   received framing 
error
+ *                                     RXPARITY:  received parity error
+ *
+ * Warnings:
+ * This function will clear the high byte flags in the Channel Status Register.
+ */
+#define rp_chan_status(ch) rp_readch2((ch), CHNOFF_CHANSTAT(ch))
+
+/*
+ * Get the low byte only of the channel status
+ *
+ * Returns 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 rp_chan_status_lo(ch) rp_readch1((ch), CHNOFF_CHANSTAT(ch))
+
+/*
+ * Purpose:  Get the number of data bytes in the Rx FIFO
+ * Returns the number of data bytes in the Rx FIFO.
+ * Comments: Byte read of count register is required to obtain Rx count.
+*/
+#define rp_get_rx_cnt(ChP) rp_readch2((ChP), CHNOFF_TXRXCOUNT(ChP))
+
+/*
+ * Returns the number of data bytes in the Tx FIFO.
+ * Comments: Byte read of count register is required to obtain Tx count.
+ */
+#define rp_get_tx_cnt(ch) rp_readch1((ch), CHNOFF_TXRXCOUNT(ch))
+
+/* Return the offset of a channel's TxRx Data register */
+#define rp_txrx_data_io(ch) CHNOFF_TXRXDATA(ch)
+
+/*
+ * Initialize a channel structure to its default state.
+ *
+ * This function must be called once for every channel structure that exists
+ * before any other SSCI calls can be made.
+ */
+#define rp_init_chan_defaults(ch) do { \
+       (ch)->sc = NULL;                \
+       (ch)->AiopNum = -1;             \
+       (ch)->ChanID = -1;              \
+       (ch)->ChanNum = -1;             \
+} while (0)
+
+#define rp_reset_aiop_by_num(sc, AIOPNUM) do {                 \
+       rp_writeaiop1((sc), (AIOPNUM), _CMD_REG, RESET_ALL);    \
+       rp_writeaiop1((sc), (AIOPNUM), _CMD_REG, 0x0);          \
+} while (0)
+
+/* Set baud rate */
+#define rp_set_baud(ch, DIVISOR) do {                          \
+       (ch)->BaudDiv[2] = (uint8_t)(DIVISOR);                  \
+       (ch)->BaudDiv[3] = (uint8_t)((DIVISOR) >> 8);           \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->BaudDiv)); \
+} while (0)
+
+/* Set data bits to 7 */
+#define rp_set_data7(ch) do {                                  \
+       (ch)->TxControl[2] &= ~DATA8BIT;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/* Set data bits to 8 */
+#define rp_set_data8(ch) do {                                  \
+       (ch)->TxControl[2] |= DATA8BIT;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/* Set the DTR output */
+#define rp_set_DTR(ch) do {                                    \
+       (ch)->TxControl[3] |= SET_DTR;                          \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/*
+ * Function sSetParity() can be used in place of functions sEnParity(),
+ * sDisParity(), rp_set_odd_parity(), and sSetEvenParity().
+ *
+ * Warnings:
+ * This function has no effect unless parity is enabled with function
+ * sEnParity().
+ */
+#define rp_set_even_parity(ch) do {                            \
+       (ch)->TxControl[2] |= EVEN_PAR;                         \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/*
+ * Function sSetParity() can be used in place of functions sEnParity(),
+ * sDisParity(), rp_set_odd_parity(), and sSetEvenParity().
+ *
+ * Warnings:
+ * This function has no effect unless parity is enabled with function
+ * sEnParity().
+ */
+#define rp_set_odd_parity(ch) do {                             \
+       (ch)->TxControl[2] &= ~EVEN_PAR;                        \
+       rp_writech4(ch, _INDX_ADDR, lemtoh32((ch)->TxControl)); \
+} while (0)
+
+/* Set the RTS output */
+#define rp_set_RTS(ch) do {                                            \
+       (ch)->TxControl[3] |= SET_RTS;                                  \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->TxControl));       \
+} while (0)
+
+/*
+ * Set the Rx FIFO trigger 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
+ *
+ * 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 rp_rx_trigger(ch, level) do {                                  \
+       (ch)->RxControl[2] &= ~TRIG_MASK;                               \
+       (ch)->RxControl[2] |= (level);                                  \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->RxControl));       \
+} while (0)
+
+/* Set stop bits to 1 */
+#define rp_set_stop1(ch) do {                                          \
+       (ch)->TxControl[2] &= ~STOP2;                                   \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->TxControl));       \
+} while (0)
+
+/* Set stop bits to 2 */
+#define rp_set_stop2(ch) do {                                          \
+       (ch)->TxControl[2] |= STOP2;                                    \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->TxControl));       \
+} while (0)
+
+/*
+ * Start a channel's receive processor
+ *
+ * This function is used to start a Rx processor after it was stopped with
+ * rp_stop_rx_processor().  It will restart both the Rx processor and software
+ * input flow control.
+ */
+#define rp_start_rx_processor(ch) \
+       rp_writech4((ch), _INDX_ADDR, lemtoh32((ch)->R))
+
+/*
+ * Write a transmit data byte to a channel.
+ *
+ * Warnings:
+ * This function writes the data byte without checking to see if sMaxTxSize is
+ * exceeded in the Tx FIFO.
+ */
+#define rp_write_tx_byte(ch, io, data) rp_writech1((ch), (io), (data))
+
+int rp_read_aiopid(struct rp_softc *, int);
+int rp_read_aiop_numchan(struct rp_softc *sc, int);
+int rp_init_chan(struct rp_softc *, struct rp_chan *, int, int);
+void rp_stop_rx_processor(struct rp_chan *);
+void rp_flush_rx_fifo(struct rp_chan *);
+void rp_flush_tx_fifo(struct rp_chan *);
+int rp_write_tx_prio_byte(struct rp_chan *, uint8_t);
+int rp_intr(void *);
+void rp_enable_interrupts(struct rp_chan *, uint16_t);
+void rp_disable_interrupts(struct rp_chan *, uint16_t);
+int rp_attach(struct rp_softc* sc, int, int);
+void rp_releaseresource(struct rp_softc *sc);
+static __inline void
+rp_lock(struct rp_softc *sc)
+{
+       if (sc->hwmtx_init != 0)
+               mtx_enter(&sc->hwmtx);
+}
+static __inline void
+rp_unlock(struct rp_softc *sc)
+{
+       if (sc->hwmtx_init != 0)
+               mtx_leave(&sc->hwmtx);
+}
+
+extern uint8_t rp_sBitMapClrTbl[8];
+extern uint8_t rp_sBitMapSetTbl[8];
+
+#define RP_UNIT(x)     dv_unit(x)
+#define MAX_RP_PORTS   128
+
+/*
+ * Port number on card encoded in low 5 bits
+ * card number in next 2 bits (only space for 4 cards)
+ * high bit reserved for dialout flag
+ */
+#define RP_PORT(x) (minor(x) & 0xf)
+#define RP_CARD(x) ((minor(x) >> 5) & 3)
+
+#define RPF_STOP 0x01
+
+struct rp_port {
+       struct tty      *rp_tty;        /* cross reference */
+       struct timeout   rp_timer;
+
+       unsigned char    state;         /* state of dtr */
+
+       int              rp_swflags;
+       int              rp_cua;
+       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;
+       struct rp_softc *rp_sc;
+       struct rp_chan   rp_channel;
+       unsigned char    TxBuf[TXFIFO_SIZE];
+       unsigned char    RxBuf[RXFIFO_SIZE];
+};
Index: sys/dev/pci/files.pci
===================================================================
RCS file: /cvs/src/sys/dev/pci/files.pci,v
retrieving revision 1.352
diff -u -p -r1.352 files.pci
--- sys/dev/pci/files.pci       17 Jul 2020 06:33:07 -0000      1.352
+++ sys/dev/pci/files.pci       2 Oct 2020 17:08:36 -0000
@@ -270,6 +270,10 @@ device     ppb: pcibus
 attach ppb at pci
 file   dev/pci/ppb.c                   ppb
 
+# Comtrol RocketPort
+attach rp at pci with rp_pci
+file   dev/pci/rp_pci.c                rp_pci
+
 # Cyclades Cyclom-8/16/32
 attach cy at pci with cy_pci
 file   dev/pci/cy_pci.c                cy_pci
Index: sys/dev/pci/pcidevs
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcidevs,v
retrieving revision 1.1933
diff -u -p -r1.1933 pcidevs
--- sys/dev/pci/pcidevs 1 Oct 2020 15:42:15 -0000       1.1933
+++ sys/dev/pci/pcidevs 2 Oct 2020 17:08:37 -0000
@@ -195,6 +195,7 @@ vendor      AD              0x11d4  Analog Devices
 vendor ZORAN           0x11de  Zoran
 vendor PIJNENBURG      0x11e3  Pijnenburg
 vendor COMPEX          0x11f6  Compex
+vendor COMCORP         0x11fe  Comtrol Corporation
 vendor CYCLADES        0x120e  Cyclades
 vendor ESSENTIAL       0x120f  Essential Communications
 vendor O2MICRO         0x1217  O2 Micro
@@ -2605,6 +2606,9 @@ product COMPAQ NF3P_BNC           0xf150  NetFlex 
 product COMPEX COMPEXE         0x1401  Compexe
 product COMPEX RL100ATX                0x2011  RL100-ATX
 product COMPEX 98713           0x9881  PMAC 98713
+
+/* Comtrol Corporation */
+product COMCORP ROCKETPORT_16  0x0009  RocketPort PCI 16-port Serial
 
 /* Conexant products */
 product CONEXANT 56K_WINMODEM  0x1033  56k Winmodem
Index: sys/dev/pci/pcidevs.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcidevs.h,v
retrieving revision 1.1926
diff -u -p -r1.1926 pcidevs.h
--- sys/dev/pci/pcidevs.h       1 Oct 2020 15:42:53 -0000       1.1926
+++ sys/dev/pci/pcidevs.h       2 Oct 2020 17:08:37 -0000
@@ -200,6 +200,7 @@
 #define        PCI_VENDOR_ZORAN        0x11de          /* Zoran */
 #define        PCI_VENDOR_PIJNENBURG   0x11e3          /* Pijnenburg */
 #define        PCI_VENDOR_COMPEX       0x11f6          /* Compex */
+#define        PCI_VENDOR_COMCORP      0x11fe          /* Comtrol Corporation 
*/
 #define        PCI_VENDOR_CYCLADES     0x120e          /* Cyclades */
 #define        PCI_VENDOR_ESSENTIAL    0x120f          /* Essential 
Communications */
 #define        PCI_VENDOR_O2MICRO      0x1217          /* O2 Micro */
@@ -2610,6 +2611,9 @@
 #define        PCI_PRODUCT_COMPEX_COMPEXE      0x1401          /* Compexe */
 #define        PCI_PRODUCT_COMPEX_RL100ATX     0x2011          /* RL100-ATX */
 #define        PCI_PRODUCT_COMPEX_98713        0x9881          /* PMAC 98713 */
+
+/* Comtrol Corporation */
+#define        PCI_PRODUCT_COMCORP_ROCKETPORT_16       0x0009          /* 
RocketPort PCI 16-port Serial */
 
 /* Conexant products */
 #define        PCI_PRODUCT_CONEXANT_56K_WINMODEM       0x1033          /* 56k 
Winmodem */
Index: sys/dev/pci/pcidevs_data.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcidevs_data.h,v
retrieving revision 1.1921
diff -u -p -r1.1921 pcidevs_data.h
--- sys/dev/pci/pcidevs_data.h  1 Oct 2020 15:42:53 -0000       1.1921
+++ sys/dev/pci/pcidevs_data.h  2 Oct 2020 17:08:37 -0000
@@ -8364,6 +8364,10 @@ static const struct pci_known_product pc
            "PMAC 98713",
        },
        {
+           PCI_VENDOR_COMCORP, PCI_PRODUCT_COMCORP_ROCKETPORT_16,
+           "RocketPort PCI 16-port Serial",
+       },
+       {
            PCI_VENDOR_CONEXANT, PCI_PRODUCT_CONEXANT_56K_WINMODEM,
            "56k Winmodem",
        },
@@ -30302,6 +30306,10 @@ static const struct pci_known_vendor pci
        {
            PCI_VENDOR_COMPEX,
            "Compex",
+       },
+       {
+           PCI_VENDOR_COMCORP,
+           "Comtrol Corporation",
        },
        {
            PCI_VENDOR_CYCLADES,

Reply via email to