summaryrefslogtreecommitdiff
path: root/sys/arch/mvme68k/dev/cl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/mvme68k/dev/cl.c')
-rw-r--r--sys/arch/mvme68k/dev/cl.c1665
1 files changed, 1665 insertions, 0 deletions
diff --git a/sys/arch/mvme68k/dev/cl.c b/sys/arch/mvme68k/dev/cl.c
new file mode 100644
index 00000000000..38f0469f53c
--- /dev/null
+++ b/sys/arch/mvme68k/dev/cl.c
@@ -0,0 +1,1665 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 provided 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 Dale Rahn.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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, 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/param.h>
+#include <sys/callout.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+/* #include <sys/queue.h> */
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <dev/cons.h>
+#include <mvme68k/dev/cd2400reg.h>
+#include <sys/syslog.h>
+#include "cl.h"
+
+#include "pcctwo.h"
+
+#if NPCCTWO > 0
+#include <mvme68k/dev/pcctworeg.h>
+#endif
+
+/* min timeout 0xa, what is a good value */
+#define CL_TIMEOUT 0x10
+#define CL_FIFO_MAX 0x10
+#define CL_FIFO_CNT 0xc
+#define CL_RX_TIMEOUT 0x10
+
+#define CL_DMAMODE 0x1
+#define CL_INTRMODE 0x0
+
+struct cl_cons {
+ u_char *cl_paddr;
+ volatile u_char *cl_vaddr;
+ volatile struct pcctworeg *pcctwoaddr;
+ u_char channel;
+} cl_cons;
+
+struct cl_info {
+ struct tty *tty;
+ u_char cl_swflags;
+ u_char cl_softchar;
+ u_char cl_consio;
+ u_char cl_speed;
+ u_char cl_parstop; /* parity, stop bits. */
+ u_char cl_rxmode;
+ u_char cl_txmode;
+ u_char cl_clen;
+ u_char cl_parity;
+ u_char transmitting;
+ u_long txcnt;
+ u_long rxcnt;
+};
+
+#define CLCD_PORTS_PER_CHIP 4
+struct clsoftc {
+ struct device sc_dev;
+ struct evcnt sc_txintrcnt;
+ struct evcnt sc_rxintrcnt;
+ struct evcnt sc_mxintrcnt;
+ time_t sc_rotime; /* time of last ring overrun */
+ time_t sc_fotime; /* time of last fifo overrun */
+ volatile u_char *vbase;
+ struct cl_info sc_cl[CLCD_PORTS_PER_CHIP];
+ struct intrhand sc_ih_e;
+ struct intrhand sc_ih_m;
+ struct intrhand sc_ih_t;
+ struct intrhand sc_ih_r;
+ struct pcctworeg *sc_pcctwo;
+ int sc_flags;
+};
+
+struct {
+ u_int speed;
+ u_char divisor;
+ u_char clock;
+ u_char rx_timeout;
+} cl_clocks[] = {
+ { 64000, 0x26, 0, 0x01},
+ { 56000, 0x2c, 0, 0x01},
+ { 38400, 0x40, 0, 0x01},
+ { 19200, 0x81, 0, 0x02},
+ { 9600, 0x40, 1, 0x04},
+ { 7200, 0x56, 1, 0x04},
+ { 4800, 0x81, 1, 0x08},
+ { 3600, 0xad, 1, 0x08},
+ { 2400, 0x40, 2, 0x10},
+ { 1200, 0x81, 2, 0x20},
+ { 600, 0x40, 3, 0x40},
+ { 300, 0x81, 3, 0x80},
+ { 150, 0x40, 3, 0x80},
+ { 110, 0x58, 4, 0xff},
+ { 50, 0xC2, 4, 0xff},
+ { 0, 0x00, 0, 0},
+};
+
+/* prototypes */
+int clcnprobe __P((struct consdev *cp));
+int clcninit __P((struct consdev *cp));
+int clcngetc __P((dev_t dev));
+int clcnputc __P((dev_t dev, char c));
+u_char cl_clkdiv __P((int speed));
+u_char cl_clknum __P((int speed));
+u_char cl_clkrxtimeout __P((int speed));
+void clstart __P((struct tty *tp));
+void cl_unblock __P((struct tty *tp));
+int clccparam __P((struct clsoftc *sc, struct termios *par, int channel));
+
+int clparam __P((struct tty *tp, struct termios *t));
+int cl_mintr __P((struct clsoftc *sc));
+int cl_txintr __P((struct clsoftc *sc));
+int cl_rxintr __P((struct clsoftc *sc));
+void cl_overflow __P((struct clsoftc *sc, int channel, long *ptime, char *msg));
+void cl_parity __P((struct clsoftc *sc, int channel));
+void cl_frame __P((struct clsoftc *sc, int channel));
+void cl_break __P(( struct clsoftc *sc, int channel));
+int clmctl __P((dev_t dev, int bits, int how));
+void cl_dumpport __P((int channel));
+
+int clprobe __P((struct device *parent, void *self, void *aux));
+void clattach __P((struct device *parent, struct device *self, void *aux));
+
+int clopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int clclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int clread __P((dev_t dev, struct uio *uio, int flag));
+int clwrite __P((dev_t dev, struct uio *uio, int flag));
+int clioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int clstop __P((struct tty *tp, int flag));
+
+static void cl_initchannel __P((struct clsoftc *sc, int channel));
+static void clputc __P((struct clsoftc *sc, int unit, char c));
+static u_char clgetc __P((struct clsoftc *sc, int *channel));
+static void cloutput __P((struct tty *tp));
+
+struct cfdriver clcd = {
+ NULL, "cl", clprobe, clattach, DV_TTY, sizeof(struct clsoftc), 0
+};
+
+#define CLCDBUF 80
+char cltty_ibuffer[CLCDBUF+1];
+char cl_obuffer[CLCDBUF+1];
+
+int dopoll = 1;
+
+#define CL_UNIT(x) (minor(x) >> 2)
+#define CL_CHANNEL(x) (minor(x) & 3)
+#define CL_TTY(x) (minor(x))
+
+extern int cputyp;
+
+struct tty *
+cltty(dev)
+ dev_t dev;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (NULL);
+ }
+ channel = CL_CHANNEL(dev);
+ return (sc->sc_cl[channel].tty);
+}
+
+/*
+ * probing onboard 166/167/187 CL-cd2400
+ * should be previously configured,
+ * we can check the value before resetting the chip
+ */
+int
+clprobe(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ volatile u_char *cd_base;
+ struct cfdata *cf = self;
+ struct confargs *ca = aux;
+ int ret;
+
+ if (cputyp != CPU_167 && cputyp != CPU_166)
+ return (0);
+
+ cd_base = ca->ca_vaddr;
+#if 0
+ return (!badvaddr(&cd_base[CD2400_GFRCR], 1));
+#endif
+ return (ret);
+}
+
+void
+clattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clsoftc *sc = (struct clsoftc *)self;
+ struct confargs *ca = aux;
+ int i;
+#if 0
+ int size = (CD2400_SIZE + PGOFSET) & ~PGOFSET;
+#endif
+
+ sc->vbase = ca->ca_vaddr;
+ sc->sc_pcctwo = ca->ca_master;
+
+ if (ca->ca_paddr == cl_cons.cl_paddr) {
+ /* if this device is configured as console,
+ * line cl_cons.channel is the console */
+ sc->sc_cl[cl_cons.channel].cl_consio = 1;
+ printf(" console");
+ } else {
+ /* reset chip only if we are not console device */
+ /* wait for GFRCR */
+ }
+ /* set up global registers */
+ sc->vbase[CD2400_TPR] = CL_TIMEOUT;
+ sc->vbase[CD2400_RPILR] = 0x03;
+ sc->vbase[CD2400_TPILR] = 0x02;
+ sc->vbase[CD2400_MPILR] = 0x01;
+
+ for (i = 0; i < CLCD_PORTS_PER_CHIP; i++) {
+#if 0
+ sc->sc_cl[i].cl_rxmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x01));
+ sc->sc_cl[i].cl_txmode =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x02));
+ sc->sc_cl[i].cl_softchar =
+ !(!((flags >> (i * CL_FLAG_BIT_PCH)) & 0x04));
+#endif
+ cl_initchannel(sc, i);
+ }
+ /* enable interrupts */
+ sc->sc_ih_e.ih_fn = cl_rxintr;
+ sc->sc_ih_e.ih_arg = sc;
+ sc->sc_ih_e.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_e.ih_wantframe = 0;
+
+ sc->sc_ih_m.ih_fn = cl_mintr;
+ sc->sc_ih_m.ih_arg = sc;
+ sc->sc_ih_m.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_m.ih_wantframe = 0;
+
+ sc->sc_ih_t.ih_fn = cl_txintr;
+ sc->sc_ih_t.ih_arg = sc;
+ sc->sc_ih_t.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_t.ih_wantframe = 0;
+
+ sc->sc_ih_r.ih_fn = cl_rxintr;
+ sc->sc_ih_r.ih_arg = sc;
+ sc->sc_ih_r.ih_ipl = ca->ca_ipl;
+ sc->sc_ih_r.ih_wantframe = 0;
+ switch (ca->ca_bustype) {
+ case BUS_PCCTWO:
+ dopoll = 0;
+ pcctwointr_establish(PCC2V_SCC_RXE, &sc->sc_ih_e);
+ pcctwointr_establish(PCC2V_SCC_M, &sc->sc_ih_m);
+ pcctwointr_establish(PCC2V_SCC_TX, &sc->sc_ih_t);
+ pcctwointr_establish(PCC2V_SCC_RX, &sc->sc_ih_r);
+ sc->sc_pcctwo = (void *)ca->ca_master;
+ sc->sc_pcctwo->pcc2_sccerr = 0x01; /* clear errors */
+
+ /* enable all interrupts at ca_ipl */
+ sc->sc_pcctwo->pcc2_sccirq = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_scctx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ sc->sc_pcctwo->pcc2_sccrx = PCC2_IRQ_IEN | (ca->ca_ipl & 0x7);
+ break;
+ }
+
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_txintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_rxintrcnt);
+ evcnt_attach(&sc->sc_dev, "intr", &sc->sc_mxintrcnt);
+ printf("\n");
+}
+
+static void
+cl_initchannel(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ int s;
+ volatile u_char *cd_base = sc->vbase;
+
+ /* set up option registers */
+ sc->sc_cl[channel].tty = NULL;
+ s = splhigh();
+ cd_base[CD2400_CAR] = (char)channel;
+ /* async, do we want to try DMA at some point? */
+ cd_base[CD2400_LIVR] = PCC2_VECBASE + 0xc;/* set vector base at 5C */
+ cd_base[CD2400_IER] = 0x88; /* should change XXX */
+ cd_base[CD2400_LICR] = 0x00; /* will change if DMA support XXX */
+ /* if the port is not the console */
+ if (sc->sc_cl[channel].cl_consio != 1) {
+ cd_base[CD2400_CMR] = 0x02;
+ cd_base[CD2400_COR1] = 0x17;
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02;
+ cd_base[CD2400_COR4] = 0xec;
+ cd_base[CD2400_COR5] = 0xec;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_RBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_RCOR] = 0x01;
+ cd_base[CD2400_TBPR] = 0x40; /* 9600 */
+ cd_base[CD2400_TCOR] = 0x01 << 5;
+ /* console port should be 0x88 already */
+ cd_base[CD2400_MSVR_RTS] = 0x00;
+ cd_base[CD2400_MSVR_DTR] = 0x00;
+ cd_base[CD2400_RTPRl] = CL_RX_TIMEOUT;
+ cd_base[CD2400_RTPRh] = 0x00;
+ }
+ splx(s);
+}
+
+int cldefaultrate = TTYDEF_SPEED;
+
+int clmctl(dev, bits, how)
+ dev_t dev;
+ int bits;
+ int how;
+{
+ struct clsoftc *sc = (struct clsoftc *)clcd.cd_devs[CL_UNIT(dev)];
+ int s;
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ } else {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ } else {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIC:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ }
+ break;
+
+ case DMBIS:
+ if (bits & TIOCM_RTS) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x01;
+ }
+ if (bits & TIOCM_DTR) {
+ sc->vbase[CD2400_MSVR_DTR] = 0x02;
+ }
+ break;
+
+ case DMGET:
+ bits = 0;
+ {
+ u_char msvr = sc->vbase[CD2400_MSVR_RTS];
+
+ if (msvr & 0x80)
+ bits |= TIOCM_DSR;
+ if (msvr & 0x40)
+ bits |= TIOCM_CD;
+ if (msvr & 0x20)
+ bits |= TIOCM_CTS;
+ if (msvr & 0x10)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x02)
+ bits |= TIOCM_DTR;
+ if (msvr & 0x01)
+ bits |= TIOCM_RTS;
+ }
+ break;
+ }
+ (void)splx(s);
+#if 0
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+#endif
+
+ /*
+ printf("retbits %x\n", bits);
+ */
+ return (bits);
+}
+
+int
+clopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int s, unit, channel;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ struct tty *tp;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ s = spltty();
+ if (cl->tty) {
+ tp = cl->tty;
+ } else {
+ tp = cl->tty = ttymalloc();
+ }
+ tp->t_oproc = clstart;
+ tp->t_param = clparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ 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 = cldefaultrate;
+ }
+ /*
+ * do these all the time
+ */
+ if (cl->cl_swflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (cl->cl_swflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (cl->cl_swflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ clparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+#ifdef XXX
+ if ((cl->cl_swflags & TIOCFLAG_SOFTCAR) ||
+ (clmctl(dev, 0, DMGET) & TIOCM_CD)) {
+ tp->t_state |= TS_CARR_ON;
+ } else {
+ tp->t_state &= ~TS_CARR_ON;
+ }
+#endif
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+#ifdef XXX
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+ if (flag & O_NONBLOCK)
+ goto done;
+#endif
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+#ifdef DEBUG
+ cl_dumpport(channel);
+#endif
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+clparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ int unit, channel;
+ struct clsoftc *sc;
+ int s;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+/*
+ t->c_ispeed = tp->t_ispeed;
+ t->c_ospeed = tp->t_ospeed;
+ t->c_cflag = tp->t_cflag;
+*/
+ clccparam(sc, t, channel);
+ s = spltty();
+ cl_unblock(tp);
+ splx(s);
+ return (0);
+}
+
+void
+cloutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt;
+ char *tptr;
+ int channel;
+ struct clsoftc *sc;
+ dev_t dev;
+
+ dev = tp->t_dev;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+ channel = CL_CHANNEL(dev);
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+/*XXX*/
+ cnt = min(CLCDBUF, cc);
+ cnt = q_to_b(&tp->t_outq, cl_obuffer, cnt);
+ if (cnt == 0) {
+ break;
+ }
+ for (tptr = cl_obuffer; tptr < &cl_obuffer[cnt]; tptr++) {
+ clputc(sc, channel, *tptr);
+ }
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+clclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+ int s;
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (cl->cl_consio == 0 && (tp->t_cflag & HUPCL) != 0) {
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+
+ splx(s);
+ ttyclose(tp);
+
+#if 0
+ cl->tty = NULL;
+#endif
+#if 0
+ cl_dumpport(channel);
+#endif
+ return (0);
+}
+
+int
+clread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+clwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+int
+clioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+ int unit, channel;
+ struct tty *tp;
+ struct cl_info *cl;
+ struct clsoftc *sc;
+
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return (ENODEV);
+ }
+ channel = CL_CHANNEL(dev);
+ cl = &sc->sc_cl[channel];
+ tp = cl->tty;
+ if (!tp)
+ return (ENXIO);
+
+ 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:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) clmctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) clmctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) clmctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = clmctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = cl->cl_swflags;
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+clstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+clcnprobe(cp)
+ struct consdev *cp;
+{
+ /* always there ? */
+ /* serial major */
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == clopen)
+ break;
+ cp->cn_dev = makedev (maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+clcninit(cp)
+ struct consdev *cp;
+{
+#ifdef MAP_DOES_WORK
+ int size = (0x1ff + PGOFSET) & ~PGOFSET;
+ int pcc2_size = (0x3C + PGOFSET) & ~PGOFSET;
+#endif
+ volatile u_char *cd_base;
+
+ cl_cons.cl_paddr = (void *)0xfff45000;
+#ifdef MAP_DOES_WORK
+ cl_cons.cl_vaddr = mapiodev(cl_cons.cl_paddr, size);
+ cd_pcc2_base = mapiodev(0xfff42000, pcc2_size);
+#else
+ cl_cons.cl_vaddr = cl_cons.cl_paddr;
+ cl_cons.pcctwoaddr = (void *)0xfff42000;
+#endif
+ cd_base = cl_cons.cl_vaddr;
+ /* reset the chip? */
+#ifdef CLCD_DO_RESET
+#endif
+#ifdef NEW_CLCD_STRUCT
+ /* set up globals */
+ cl->tftc = 0x10;
+ cl->tpr = CL_TIMEOUT; /* is this correct?? */
+ cl->rpilr = 0x03;
+ cl->tpilr = 0x02;
+ cl->mpilr = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cl->car = 0x00;
+ cl->cor1 = 0x17; /* No parity, ignore parity, 8 bit char */
+ cl->cor2 = 0x00;
+ cl->cor3 = 0x02; /* 1 stop bit */
+ cl->cor4 = 0x00;
+ cl->cor5 = 0x00;
+ cl->cor6 = 0x00;
+ cl->cor7 = 0x00;
+ cl->schr1 = 0x00;
+ cl->schr2 = 0x00;
+ cl->schr3 = 0x00;
+ cl->schr4 = 0x00;
+ cl->scrl = 0x00;
+ cl->scrh = 0x00;
+ cl->lnxt = 0x00;
+ cl->cpsr = 0x00;
+#else
+ /* set up globals */
+#ifdef NOT_ALREADY_SETUP
+ cd_base[CD2400_TFTC] = 0x10;
+ cd_base[CD2400_TPR] = CL_TIMEOUT; /* is this correct?? */
+ cd_base[CD2400_RPILR] = 0x03;
+ cd_base[CD2400_TPILR] = 0x02;
+ cd_base[CD2400_MPILR] = 0x01;
+
+ /* set up the tty00 to be 9600 8N1 */
+ cd_base[CD2400_CAR] = 0x00;
+ cd_base[CD2400_COR1] = 0x17; /* No parity, ignore parity, 8 bit char */
+ cd_base[CD2400_COR2] = 0x00;
+ cd_base[CD2400_COR3] = 0x02; /* 1 stop bit */
+ cd_base[CD2400_COR4] = 0x00;
+ cd_base[CD2400_COR5] = 0x00;
+ cd_base[CD2400_COR6] = 0x00;
+ cd_base[CD2400_COR7] = 0x00;
+ cd_base[CD2400_SCHR1] = 0x00;
+ cd_base[CD2400_SCHR2] = 0x00;
+ cd_base[CD2400_SCHR3] = 0x00;
+ cd_base[CD2400_SCHR4] = 0x00;
+ cd_base[CD2400_SCRl] = 0x00;
+ cd_base[CD2400_SCRh] = 0x00;
+ cd_base[CD2400_LNXT] = 0x00;
+ cd_base[CD2400_CPSR] = 0x00;
+#endif
+#endif
+ return (0);
+}
+
+int
+cl_instat(sc)
+ struct clsoftc *sc;
+{
+ volatile u_char *cd_base;
+
+ if ( NULL == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+ return (cd_base[CD2400_RIR] & 0x80);
+}
+
+int
+clcngetc(dev)
+ dev_t dev;
+{
+ u_char val, reoir, licr, isrl, data, status, fifo_cnt;
+ int got_char = 0;
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ volatile struct pcctworeg *pcc2_base = cl_cons.pcctwoaddr;
+
+ while (got_char == 0) {
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ continue;
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ if (((licr >> 2) & 0x3) == 0) {
+ /* is the interrupt for us (port 0) */
+ /* the character is for us. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ data = cd_base[CD2400_RDR];
+ got_char = 1;
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ }
+
+ }
+ return (data);
+}
+
+int
+clcnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ /* is this the correct location for the cr -> cr/lf tranlation? */
+ if (c == '\n')
+ clputc(0, 0, '\r');
+
+ clputc(0, 0, c);
+ return (0);
+}
+
+clcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+ if (1 == on) {
+ /* enable polling */
+ } else {
+ /* disable polling */
+ }
+}
+
+static void
+clputc(sc, unit, c)
+ struct clsoftc *sc;
+ int unit;
+ char c;
+{
+ int s;
+ u_char schar;
+ u_char oldchannel;
+ volatile u_char *cd_base;
+ if (0 == sc) {
+ /* output on console */
+ cd_base = cl_cons.cl_vaddr;
+ } else {
+ cd_base = sc->vbase;
+ }
+#ifdef NEW_CLCD_STRUCT
+ /* should we disable, flush and all that goo? */
+ cl->car = unit;
+ schar = cl->schr3;
+ cl->schr3 = c;
+ cl->stcr = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cl->stcr) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ cl->schr3 = schar;
+#else
+if (unit == 0) {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ schar = cd_base[CD2400_SCHR3];
+ cd_base[CD2400_SCHR3] = c;
+ cd_base[CD2400_STCR] = 0x08 | 0x03; /* send special char, char 3 */
+ while (0 != cd_base[CD2400_STCR]) {
+ /* wait until cl notices the command
+ * otherwise it may not notice the character
+ * if we send characters too fast.
+ */
+ }
+ DELAY(5);
+ cd_base[CD2400_SCHR3] = schar;
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+} else {
+ s = splhigh();
+ oldchannel = cd_base[CD2400_CAR];
+ cd_base[CD2400_CAR] = unit;
+ if (cd_base[CD2400_TFTC] > 0) {
+ cd_base[CD2400_TDR] = c;
+ }
+ cd_base[CD2400_CAR] = oldchannel;
+ splx(s);
+}
+#endif
+}
+
+/*
+#ifdef CLCD_DO_POLLED_INPUT
+*/
+#if 1
+void
+cl_chkinput()
+{
+ struct tty *tp;
+ int unit;
+ struct clsoftc *sc;
+ int channel;
+
+ if (dopoll == 0)
+ return;
+ for (unit = 0; unit < clcd.cd_ndevs; unit++) {
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ continue;
+ }
+ if (cl_instat(sc)) {
+ while (cl_instat(sc)){
+ int ch;
+ u_char c;
+ /*
+ *(pinchar++) = clcngetc();
+ */
+ ch = clgetc(sc, &channel) & 0xff;
+ c = ch;
+
+ tp = sc->sc_cl[channel].tty;
+ if (NULL != tp) {
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+ }
+}
+#endif
+
+static u_char
+clgetc(sc, channel)
+ struct clsoftc *sc;
+ int *channel;
+{
+ volatile u_char *cd_base;
+ volatile struct pcctworeg *pcc2_base;
+ u_char val, reoir, licr, isrl, fifo_cnt, data;
+
+ if (0 == sc) {
+ cd_base = cl_cons.cl_vaddr;
+ pcc2_base = cl_cons.pcctwoaddr;
+ } else {
+ cd_base = sc->vbase;
+ pcc2_base = sc->sc_pcctwo;
+ }
+ val = cd_base[CD2400_RIR];
+ /* if no receive interrupt pending wait */
+ if (!(val & 0x80)) {
+ return (0);
+ }
+ /* XXX do we need to suck the entire FIFO contents? */
+ reoir = pcc2_base->pcc2_sccrxiack; /* receive PIACK */
+ licr = cd_base[CD2400_LICR];
+ *channel = (licr >> 2) & 0x3;
+ /* is the interrupt for us (port 0) */
+ /* the character is for us yea. */
+ isrl = cd_base[CD2400_RISRl];
+#if 0
+ if (isrl & 0x01) {
+ status = BREAK;
+ }
+ if (isrl & 0x02) {
+ status = FRAME;
+ }
+ if (isrl & 0x04) {
+ status = PARITY;
+ }
+ if (isrl & 0x08) {
+ status = OVERFLOW;
+ }
+ /* we do not have special characters ;-) */
+#endif
+ fifo_cnt = cd_base[CD2400_RFOC];
+ if (fifo_cnt > 0) {
+ data = cd_base[CD2400_RDR];
+ cd_base[CD2400_TEOIR] = 0x00;
+ } else {
+ data = 0;
+ cd_base[CD2400_TEOIR] = 0x08;
+ }
+ return (data);
+}
+
+int
+clccparam(sc, par, channel)
+ struct clsoftc *sc;
+ struct termios *par;
+ int channel;
+{
+ u_int divisor, clk, clen;
+ int s, imask, ints;
+
+ s = spltty();
+ sc->vbase[CD2400_CAR] = channel;
+ if (par->c_ospeed == 0) {
+ /* dont kill the console */
+ if (sc->sc_cl[channel].cl_consio == 0) {
+ /* disconnect, drop RTS DTR stop reciever */
+ sc->vbase[CD2400_MSVR_RTS] = 0x00;
+ sc->vbase[CD2400_MSVR_DTR] = 0x00;
+ sc->vbase[CD2400_CCR] = 0x05;
+ }
+ splx(s);
+ return (0xff);
+ }
+
+ sc->vbase[CD2400_MSVR_RTS] = 0x03;
+ sc->vbase[CD2400_MSVR_DTR] = 0x03;
+
+ divisor = cl_clkdiv(par->c_ospeed);
+ clk = cl_clknum(par->c_ospeed);
+ sc->vbase[CD2400_TBPR] = divisor;
+ sc->vbase[CD2400_TCOR] = clk << 5;
+ divisor = cl_clkdiv(par->c_ispeed);
+ clk = cl_clknum(par->c_ispeed);
+ sc->vbase[CD2400_RBPR] = divisor;
+ sc->vbase[CD2400_RCOR] = clk;
+ sc->vbase[CD2400_RTPRl] = cl_clkrxtimeout(par->c_ispeed);
+ sc->vbase[CD2400_RTPRh] = 0x00;
+
+ switch (par->c_cflag & CSIZE) {
+ case CS5:
+ clen = 4; /* this is the mask for the chip. */
+ imask = 0x1F;
+ break;
+ case CS6:
+ clen = 5;
+ imask = 0x3F;
+ break;
+ case CS7:
+ clen = 6;
+ imask = 0x7F;
+ break;
+ default:
+ clen = 7;
+ imask = 0xFF;
+ }
+ sc->vbase[CD2400_COR3] = par->c_cflag & PARENB ? 4 : 2;
+
+ if (par->c_cflag & PARENB) {
+ if (par->c_cflag & PARODD) {
+ sc->vbase[CD2400_COR1] = 0xE0 | clen ; /* odd */
+ } else {
+ sc->vbase[CD2400_COR1] = 0x40 | clen ; /* even */
+ }
+ } else {
+ sc->vbase[CD2400_COR1] = 0x10 | clen; /* ignore parity */
+ }
+
+ if (sc->sc_cl[channel].cl_consio == 0 &&
+ (par->c_cflag & CREAD) == 0 ) {
+/*
+ sc->vbase[CD2400_CSR] = 0x08;
+*/
+ sc->vbase[CD2400_CCR] = 0x08;
+ } else {
+ sc->vbase[CD2400_CCR] = 0x0a;
+ }
+ ints = 0;
+#define SCC_DSR 0x80
+#define SCC_DCD 0x40
+#define SCC_CTS 0x20
+ if ((par->c_cflag & CLOCAL) == 0) {
+ ints |= SCC_DCD;
+ }
+ if ((par->c_cflag & CCTS_OFLOW) != 0) {
+ ints |= SCC_CTS;
+ }
+ if ((par->c_cflag & CRTSCTS) != 0) {
+ ints |= SCC_CTS;
+ }
+#ifdef DONT_LET_HARDWARE
+ if ((par->c_cflag & CCTS_IFLOW) != 0) {
+ ints |= SCC_DSR;
+ }
+#endif
+ sc->vbase[CD2400_COR4] = ints | CL_FIFO_CNT;
+ sc->vbase[CD2400_COR5] = ints | CL_FIFO_CNT;
+ return (imask);
+}
+
+static int clknum = 0;
+
+u_char
+cl_clkdiv(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].divisor);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].divisor);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].divisor);
+}
+
+u_char
+cl_clknum(speed)
+ int speed;
+{
+ int found = 0;
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].clock);
+ }
+ for (i = 0; found != 0 && cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[clknum].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].clock);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].clock);
+}
+
+u_char
+cl_clkrxtimeout(speed)
+ int speed;
+{
+ int i = 0;
+
+ if (cl_clocks[clknum].speed == speed) {
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ for (i = 0; cl_clocks[i].speed != 0; i++) {
+ if (cl_clocks[i].speed == speed) {
+ clknum = i;
+ return (cl_clocks[clknum].rx_timeout);
+ }
+ }
+ /* return some sane value if unknown speed */
+ return (cl_clocks[4].rx_timeout);
+}
+
+void
+cl_unblock(tp)
+ struct tty *tp;
+{
+ tp->t_state &= ~TS_FLUSH;
+ if (tp->t_outq.c_cc != 0)
+ clstart(tp);
+}
+
+void
+clstart(tp)
+ struct tty *tp;
+{
+ dev_t dev;
+ u_char cbuf;
+ struct clsoftc *sc;
+ int channel, unit, s, cnt;
+
+ dev = tp->t_dev;
+ channel = CL_CHANNEL(dev);
+/* hack to test output on non console only */
+#if 0
+ if (channel == 0) {
+ cloutput(tp);
+ return;
+ }
+#endif
+ unit = CL_UNIT(dev);
+ if (unit >= clcd.cd_ndevs ||
+ (sc = (struct clsoftc *) clcd.cd_devs[unit]) == NULL) {
+ return;
+ }
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+#if 0
+ if (sc->sc_cl[channel].transmitting == 1) {
+ /* i'm busy, go away, I will get to it later. */
+ splx(s);
+ return;
+ }
+ cnt = q_to_b(&tp->t_outq, &cbuf, 1);
+ if (cnt != 0) {
+ sc->sc_cl[channel].transmitting = 1;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_TDR] = cbuf;
+ } else {
+ sc->sc_cl[channel].transmitting = 0;
+ }
+#else
+ if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_FLUSH)) == 0) {
+ tp->t_state |= TS_BUSY;
+ sc->vbase[CD2400_CAR] = channel;
+ sc->vbase[CD2400_IER] = 0xb;
+ }
+#endif
+ splx(s);
+}
+
+int
+cl_mintr(sc)
+ struct clsoftc *sc;
+{
+ u_char mir, misr, msvr;
+ int channel;
+ struct tty *tp;
+
+ mir = sc->vbase[CD2400_MIR];
+ if ((mir & 0x40) == 0x0) {
+ /* only if intr is not shared? */
+ printf("cl_mintr extra intr\n");
+ return (0);
+ }
+ sc->sc_mxintrcnt.ev_count++;
+
+ channel = mir & 0x03;
+ misr = sc->vbase[CD2400_MISR];
+ msvr = sc->vbase[CD2400_MSVR_RTS];
+ if (misr & 0x01) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 1 unexpected\n", channel);
+ }
+ if (misr & 0x02) {
+ /* timers are not currently used?? */
+ printf("cl_mintr: channel %x timer 2 unexpected\n", channel);
+ }
+ if (misr & 0x20) {
+ printf("cl_mintr: channel %x cts %x\n", channel,
+ (msvr & 0x20) != 0x0);
+ }
+ if (misr & 0x40) {
+ struct tty *tp = sc->sc_cl[channel].tty;
+
+ printf("cl_mintr: channel %x cd %x\n", channel,
+ (msvr & 0x40) != 0x0);
+ ttymodem(tp, (msvr & 0x40) != 0x0);
+ }
+ if (misr & 0x80) {
+ printf("cl_mintr: channel %x dsr %x\n", channel,
+ (msvr & 0x80) != 0x0);
+ }
+ sc->vbase[CD2400_MEOIR] = 0x00;
+ return (1);
+}
+
+int
+cl_txintr(sc)
+ struct clsoftc *sc;
+{
+ static empty = 0;
+ u_char tir, licr, teoir;
+ u_char max;
+ int channel;
+ struct tty *tp;
+ int cnt;
+ u_char buffer[CL_FIFO_MAX +1];
+ u_char *tptr;
+
+ tir = sc->vbase[CD2400_TIR];
+ if ((tir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_txintr extra intr\n");
+ return (0);
+ }
+ sc->sc_txintrcnt.ev_count++;
+
+ channel = tir & 0x03;
+ licr = sc->vbase[CD2400_LICR];
+
+ sc->sc_cl[channel].txcnt ++;
+
+ tp = sc->sc_cl[channel].tty;
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+ sc->vbase[CD2400_TEOIR] = 0x08;
+ return (1);
+ }
+ switch ((licr >> 4) & 0x3) {
+ case CL_DMAMODE:
+ teoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ max = sc->vbase[CD2400_TFTC];
+ cnt = min((int)max, tp->t_outq.c_cc);
+ if (cnt != 0) {
+ cnt = q_to_b(&tp->t_outq, buffer, cnt);
+ empty = 0;
+ for (tptr = buffer; tptr < &buffer[cnt]; tptr++) {
+ sc->vbase[CD2400_TDR]= *tptr;
+ }
+ teoir = 0x00;
+ } else {
+ if (empty > 5 && (empty % 20000 ) == 0) {
+ printf("cl_txintr: too many empty intr %d chan %d\n",
+ empty, channel);
+ }
+ empty++;
+ teoir = 0x08;
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ sc->vbase[CD2400_IER] = sc->vbase[CD2400_IER] & ~0x3;
+ }
+ break;
+ default:
+ printf("cl_txintr unknown mode %x\n", (licr >> 4) & 0x3);
+ /* we probably will go to hell quickly now */
+ teoir = 0x08;
+ }
+ sc->vbase[CD2400_TEOIR] = teoir;
+ return (1);
+}
+
+int
+cl_rxintr(sc)
+ struct clsoftc *sc;
+{
+ u_char rir, channel, licr, risrl;
+ u_char c;
+ u_char fifocnt;
+ struct tty *tp;
+ int i;
+ u_char reoir;
+
+ rir = sc->vbase[CD2400_RIR];
+ if ((rir & 0x40) == 0x0) {
+ /* only if intr is not shared ??? */
+ printf("cl_rxintr extra intr\n");
+ return (0);
+ }
+ sc->sc_rxintrcnt.ev_count++;
+ channel = rir & 0x3;
+ licr = sc->vbase[CD2400_LICR];
+ reoir = 0x08;
+
+ sc->sc_cl[channel].rxcnt ++;
+
+ switch (licr & 0x03) {
+ case CL_DMAMODE:
+ reoir = 0x08;
+ break;
+ case CL_INTRMODE:
+ risrl = sc->vbase[CD2400_RISRl];
+ if (risrl & 0x80) {
+ /* timeout, no characters */
+ reoir = 0x08;
+ } else
+ /* We don't need no sinkin special characters */
+ if (risrl & 0x08) {
+ cl_overflow (sc, channel, &sc->sc_fotime, "fifo");
+ reoir = 0x08;
+ } else
+ if (risrl & 0x04) {
+ cl_parity(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x02) {
+ cl_frame(sc, channel);
+ reoir = 0x08;
+ } else
+ if (risrl & 0x01) {
+ cl_break(sc, channel);
+ reoir = 0x08;
+ } else {
+ fifocnt = sc->vbase[CD2400_RFOC];
+ tp = sc->sc_cl[channel].tty;
+ for (i = 0; i < fifocnt; i++) {
+ c = sc->vbase[CD2400_RDR];
+#if USE_BUFFER
+ cl_appendbuf(sc, channel, c);
+#else
+ /* does any restricitions exist on spl
+ * for this call
+ */
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ reoir = 0x00;
+#endif
+ }
+ }
+ break;
+ default:
+ printf("cl_rxintr unknown mode %x\n", licr & 0x03);
+ /* we probably will go to hell quickly now */
+ reoir = 0x08;
+ }
+ sc->vbase[CD2400_REOIR] = reoir;
+ return (1);
+}
+
+void
+cl_overflow(sc, channel, ptime, msg)
+ struct clsoftc *sc;
+ int channel;
+ long *ptime;
+ char *msg;
+{
+/*
+ if (*ptime != time.tv_sec) {
+*/
+ {
+/*
+ *ptime = time.tv_sec);
+*/
+ log(LOG_WARNING, "%s%d[%d]: %s overrun", clcd.cd_name,
+ 0 /* fix */, channel, msg);
+ }
+}
+
+void
+cl_parity(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: parity error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_frame(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: frame error", clcd.cd_name, 0, channel);
+}
+
+void
+cl_break(sc, channel)
+ struct clsoftc *sc;
+ int channel;
+{
+ log(LOG_WARNING, "%s%d[%d]: break detected", clcd.cd_name, 0, channel);
+}
+
+void
+cl_dumpport0()
+{
+ cl_dumpport(0);
+}
+
+void
+cl_dumpport1()
+{
+ cl_dumpport(1);
+}
+
+void
+cl_dumpport2()
+{
+ cl_dumpport(2);
+}
+
+void
+cl_dumpport3()
+{
+ cl_dumpport(3);
+}
+
+void
+cl_dumpport(channel)
+ int channel;
+{
+ u_char livr, cmr, cor1, cor2, cor3, cor4, cor5, cor6, cor7;
+ u_char schr1, schr2, schr3, schr4, scrl, scrh, lnxt;
+ u_char rbpr, rcor, tbpr, tcor, rpilr, rir, tpr, ier, ccr;
+ u_char csr, rts, dtr, rtprl, rtprh;
+ struct clsoftc *sc = (struct clsoftc *) clcd.cd_devs[0];
+ volatile u_char *cd_base = cl_cons.cl_vaddr;
+ int s;
+
+ s = spltty();
+ cd_base[CD2400_CAR] = (char) channel;
+ livr = cd_base[CD2400_LIVR];
+ cmr = cd_base[CD2400_CMR];
+ cor1 = cd_base[CD2400_COR1];
+ cor2 = cd_base[CD2400_COR2];
+ cor3 = cd_base[CD2400_COR3];
+ cor4 = cd_base[CD2400_COR4];
+ cor5 = cd_base[CD2400_COR5];
+ cor6 = cd_base[CD2400_COR6];
+ cor7 = cd_base[CD2400_COR7];
+ schr1 = cd_base[CD2400_SCHR1];
+ schr2 = cd_base[CD2400_SCHR2];
+ schr3 = cd_base[CD2400_SCHR3];
+ schr4 = cd_base[CD2400_SCHR4];
+ scrl = cd_base[CD2400_SCRl];
+ scrh = cd_base[CD2400_SCRh];
+ lnxt = cd_base[CD2400_LNXT];
+ rbpr = cd_base[CD2400_RBPR];
+ rcor = cd_base[CD2400_RCOR];
+ tbpr = cd_base[CD2400_TBPR];
+ rpilr = cd_base[CD2400_RPILR];
+ ier = cd_base[CD2400_IER];
+ ccr = cd_base[CD2400_CCR];
+ tcor = cd_base[CD2400_TCOR];
+ csr = cd_base[CD2400_CSR];
+ tpr = cd_base[CD2400_TPR];
+ rts = cd_base[CD2400_MSVR_RTS];
+ dtr = cd_base[CD2400_MSVR_DTR];
+ rtprl = cd_base[CD2400_RTPRl];
+ rtprh = cd_base[CD2400_RTPRh];
+ splx(s);
+
+ printf("{ port %x livr %x cmr %x\n", channel, livr, cmr);
+ printf("cor1 %x cor2 %x cor3 %x cor4 %x cor5 %x cor6 %x cor7 %x\n",
+ cor1, cor2, cor3, cor4, cor5, cor6, cor7);
+ printf("schr1 %x schr2 %x schr3 %x schr4 %x\n", schr1, schr2, schr3,
+ schr4);
+ printf("scrl %x scrh %x lnxt %x\n", scrl, scrh, lnxt);
+ printf("rbpr %x rcor %x tbpr %x tcor %x\n", rbpr, rcor, tbpr, tcor);
+ printf("rpilr %x rir %x ier %x ccr %x\n", rpilr, rir, ier, ccr);
+ printf("tpr %x csr %x rts %x dtr %x\n", tpr, csr, rts, dtr);
+ printf("rtprl %x rtprh %x\n", rtprl, rtprh);
+ printf("rxcnt %x txcnt %x\n", sc->sc_cl[channel].rxcnt,
+ sc->sc_cl[channel].txcnt);
+ printf("}\n");
+}