strategy returns void, ioctl cmd is u_long
[unix-history] / usr / src / sys / hp / dev / dca.c
index 67f189e..1ee342c 100644 (file)
@@ -1,47 +1,72 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)dca.c       7.3 (Berkeley) %G%
+ *     @(#)dca.c       8.3 (Berkeley) %G%
  */
 
 #include "dca.h"
 #if NDCA > 0
 /*
  */
 
 #include "dca.h"
 #if NDCA > 0
 /*
- *  98626/98644/internal serial interface
+ *  Driver for National Semiconductor INS8250/NS16550AF/WD16C552 UARTs.
+ *  Includes:
+ *     98626/98644/internal serial interface on hp300/hp400
+ *     internal serial ports on hp700
+ *
+ *  N.B. On the hp700, there is a "secret bit" with undocumented behavior.
+ *  The third bit of the Modem Control Register (MCR_IEN == 0x08) must be
+ *  set to enable interrupts.
  */
  */
-#include "param.h"
-#include "systm.h"
-#include "ioctl.h"
-#include "tty.h"
-#include "user.h"
-#include "conf.h"
-#include "file.h"
-#include "uio.h"
-#include "kernel.h"
-#include "syslog.h"
-
-#include "device.h"
-#include "dcareg.h"
-#include "machine/cpu.h"
-#include "machine/isr.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <hp/dev/device.h>
+#include <hp/dev/dcareg.h>
+
+#include <machine/cpu.h>
+#ifdef hp300
+#include <hp300/hp300/isr.h>
+#endif
+#ifdef hp700
+#include <machine/asp.h>
+#endif
 
 int    dcaprobe();
 struct driver dcadriver = {
        dcaprobe, "dca",
 };
 
 
 int    dcaprobe();
 struct driver dcadriver = {
        dcaprobe, "dca",
 };
 
-int    dcastart(), dcaparam(), dcaintr();
+void   dcastart();
+int    dcaparam(), dcaintr();
 int    dcasoftCAR;
 int    dca_active;
 int    dcasoftCAR;
 int    dca_active;
+int    dca_hasfifo;
 int    ndca = NDCA;
 int    ndca = NDCA;
+#ifdef DCACONSOLE
+int    dcaconsole = DCACONSOLE;
+#else
 int    dcaconsole = -1;
 int    dcaconsole = -1;
+#endif
+int    dcaconsinit;
 int    dcadefaultrate = TTYDEF_SPEED;
 int    dcadefaultrate = TTYDEF_SPEED;
+int    dcamajor;
 struct dcadevice *dca_addr[NDCA];
 struct tty dca_tty[NDCA];
 struct dcadevice *dca_addr[NDCA];
 struct tty dca_tty[NDCA];
+#ifdef hp300
 struct isr dcaisr[NDCA];
 struct isr dcaisr[NDCA];
+int    dcafastservice;
+#endif
+int    dcaoflows[NDCA];
 
 struct speedtab dcaspeedtab[] = {
        0,      0,
 
 struct speedtab dcaspeedtab[] = {
        0,      0,
@@ -63,15 +88,23 @@ struct speedtab dcaspeedtab[] = {
        -1,     -1
 };
 
        -1,     -1
 };
 
-extern struct tty *constty;
 #ifdef KGDB
 #ifdef KGDB
-extern int kgdb_dev;
+#include <machine/remote-sl.h>
+
+extern dev_t kgdb_dev;
 extern int kgdb_rate;
 extern int kgdb_debug_init;
 #endif
 
 #define        UNIT(x)         minor(x)
 
 extern int kgdb_rate;
 extern int kgdb_debug_init;
 #endif
 
 #define        UNIT(x)         minor(x)
 
+#ifdef DEBUG
+long   fifoin[17];
+long   fifoout[17];
+long   dcaintrcount[16];
+long   dcamintcount[16];
+#endif
+
 dcaprobe(hd)
        register struct hp_device *hd;
 {
 dcaprobe(hd)
        register struct hp_device *hd;
 {
@@ -79,60 +112,84 @@ dcaprobe(hd)
        register int unit;
 
        dca = (struct dcadevice *)hd->hp_addr;
        register int unit;
 
        dca = (struct dcadevice *)hd->hp_addr;
-       if (dca->dca_irid != DCAID0 &&
-           dca->dca_irid != DCAREMID0 &&
-           dca->dca_irid != DCAID1 &&
-           dca->dca_irid != DCAREMID1)
+#ifdef hp300
+       if (dca->dca_id != DCAID0 &&
+           dca->dca_id != DCAREMID0 &&
+           dca->dca_id != DCAID1 &&
+           dca->dca_id != DCAREMID1)
                return (0);
                return (0);
+#endif
        unit = hd->hp_unit;
        if (unit == dcaconsole)
                DELAY(100000);
        unit = hd->hp_unit;
        if (unit == dcaconsole)
                DELAY(100000);
-       dca->dca_irid = 0xFF;
+#ifdef hp300
+       dca->dca_reset = 0xFF;
+       DELAY(100);
+#endif
+
+       /* look for a NS 16550AF UART with FIFOs */
+       dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
        DELAY(100);
        DELAY(100);
+       if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
+               dca_hasfifo |= 1 << unit;
 
 
+       dca_addr[unit] = dca;
+#ifdef hp300
        hd->hp_ipl = DCAIPL(dca->dca_ic);
        dcaisr[unit].isr_ipl = hd->hp_ipl;
        dcaisr[unit].isr_arg = unit;
        dcaisr[unit].isr_intr = dcaintr;
        hd->hp_ipl = DCAIPL(dca->dca_ic);
        dcaisr[unit].isr_ipl = hd->hp_ipl;
        dcaisr[unit].isr_arg = unit;
        dcaisr[unit].isr_intr = dcaintr;
-       dca_addr[unit] = dca;
-       dca_active |= 1 << unit;
-       dcasoftCAR = hd->hp_flags;
        isrlink(&dcaisr[unit]);
        isrlink(&dcaisr[unit]);
+#endif
+       dca_active |= 1 << unit;
+       if (hd->hp_flags)
+               dcasoftCAR |= (1 << unit);
 #ifdef KGDB
 #ifdef KGDB
-       if (kgdb_dev == makedev(1, unit)) {
+       if (kgdb_dev == makedev(dcamajor, unit)) {
                if (dcaconsole == unit)
                if (dcaconsole == unit)
-                       kgdb_dev = -1;  /* can't debug over console port */
+                       kgdb_dev = NODEV; /* can't debug over console port */
                else {
                else {
-                       (void) dcainit(unit);
-                       dcaconsole = -2; /* XXX */
+                       (void) dcainit(unit, kgdb_rate);
+                       dcaconsinit = 1;        /* don't re-init in dcaputc */
                        if (kgdb_debug_init) {
                        if (kgdb_debug_init) {
-                               printf("dca%d: kgdb waiting...", unit);
-                               /* trap into kgdb */
-                               asm("trap #15;");
-                               printf("connected.\n");
+                               /*
+                                * Print prefix of device name,
+                                * let kgdb_connect print the rest.
+                                */
+                               printf("dca%d: ", unit);
+                               kgdb_connect(1);
                        } else
                                printf("dca%d: kgdb enabled\n", unit);
                }
        }
 #endif
                        } else
                                printf("dca%d: kgdb enabled\n", unit);
                }
        }
 #endif
+#ifdef hp300
        dca->dca_ic = IC_IE;
        dca->dca_ic = IC_IE;
+#endif
        /*
        /*
-        * Need to reset baud rate, etc. of next print so reset dcaconsole.
-        * Also make sure console is always "hardwired"
+        * Need to reset baud rate, etc. of next print so reset dcaconsinit.
+        * Also make sure console is always "hardwired."
         */
        if (unit == dcaconsole) {
         */
        if (unit == dcaconsole) {
-               dcaconsole = -1;
+               dcaconsinit = 0;
                dcasoftCAR |= (1 << unit);
        }
        return (1);
 }
 
                dcasoftCAR |= (1 << unit);
        }
        return (1);
 }
 
-dcaopen(dev, flag)
+/* ARGSUSED */
+#ifdef __STDC__
+dcaopen(dev_t dev, int flag, int mode, struct proc *p)
+#else
+dcaopen(dev, flag, mode, p)
        dev_t dev;
        dev_t dev;
+       int flag, mode;
+       struct proc *p;
+#endif
 {
        register struct tty *tp;
        register int unit;
 {
        register struct tty *tp;
        register int unit;
-       int error;
+       int error = 0;
  
        unit = UNIT(dev);
        if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
  
        unit = UNIT(dev);
        if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
@@ -142,75 +199,104 @@ dcaopen(dev, flag)
        tp->t_param = dcaparam;
        tp->t_dev = dev;
        if ((tp->t_state & TS_ISOPEN) == 0) {
        tp->t_param = dcaparam;
        tp->t_dev = dev;
        if ((tp->t_state & TS_ISOPEN) == 0) {
+               tp->t_state |= TS_WOPEN;
                ttychars(tp);
                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 = dcadefaultrate;
+               if (tp->t_ispeed == 0) {
+                       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 = dcadefaultrate;
+               }
                dcaparam(tp, &tp->t_termios);
                ttsetwater(tp);
                dcaparam(tp, &tp->t_termios);
                ttsetwater(tp);
-       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+       } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
                return (EBUSY);
        (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
        if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
                tp->t_state |= TS_CARR_ON;
        (void) spltty();
                return (EBUSY);
        (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
        if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
                tp->t_state |= TS_CARR_ON;
        (void) spltty();
-       while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
+       while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
               (tp->t_state & TS_CARR_ON) == 0) {
                tp->t_state |= TS_WOPEN;
               (tp->t_state & TS_CARR_ON) == 0) {
                tp->t_state |= TS_WOPEN;
-               if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
-                                  ttopen, 0)) ||
-                   (error = ttclosed(tp))) {
-                       tp->t_state &= ~TS_WOPEN;
-                       (void) spl0();
-                       return (error);
-               }
+               if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+                   ttopen, 0))
+                       break;
        }
        (void) spl0();
        }
        (void) spl0();
-       return ((*linesw[tp->t_line].l_open)(dev, tp));
+       if (error == 0)
+               error = (*linesw[tp->t_line].l_open)(dev, tp);
+#ifdef hp300
+       /*
+        * XXX hack to speed up unbuffered builtin port.
+        * If dca_fastservice is set, a level 5 interrupt
+        * will be directed to dcaintr first.
+        */
+       if (error == 0 && unit == 0 && (dca_hasfifo & 1) == 0)
+               dcafastservice = 1;
+#endif
+       return (error);
 }
  
 /*ARGSUSED*/
 }
  
 /*ARGSUSED*/
-dcaclose(dev, flag)
+dcaclose(dev, flag, mode, p)
        dev_t dev;
        dev_t dev;
+       int flag, mode;
+       struct proc *p;
 {
        register struct tty *tp;
        register struct dcadevice *dca;
        register int unit;
  
        unit = UNIT(dev);
 {
        register struct tty *tp;
        register struct dcadevice *dca;
        register int unit;
  
        unit = UNIT(dev);
+#ifdef hp300
+       if (unit == 0)
+               dcafastservice = 0;
+#endif
        dca = dca_addr[unit];
        tp = &dca_tty[unit];
        dca = dca_addr[unit];
        tp = &dca_tty[unit];
-       (*linesw[tp->t_line].l_close)(tp);
+       (*linesw[tp->t_line].l_close)(tp, flag);
        dca->dca_cfcr &= ~CFCR_SBREAK;
 #ifdef KGDB
        /* do not disable interrupts if debugging */
        dca->dca_cfcr &= ~CFCR_SBREAK;
 #ifdef KGDB
        /* do not disable interrupts if debugging */
-       if (kgdb_dev != makedev(1, unit))
+       if (dev != kgdb_dev)
 #endif
        dca->dca_ier = 0;
 #endif
        dca->dca_ier = 0;
-       if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 
+       if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
            (tp->t_state&TS_ISOPEN) == 0)
                (void) dcamctl(dev, 0, DMSET);
        ttyclose(tp);
            (tp->t_state&TS_ISOPEN) == 0)
                (void) dcamctl(dev, 0, DMSET);
        ttyclose(tp);
-       return(0);
+       return (0);
 }
  
 dcaread(dev, uio, flag)
        dev_t dev;
        struct uio *uio;
 }
  
 dcaread(dev, uio, flag)
        dev_t dev;
        struct uio *uio;
+       int flag;
 {
 {
-       register struct tty *tp = &dca_tty[UNIT(dev)];
+       int unit = UNIT(dev);
+       register struct tty *tp = &dca_tty[unit];
+       int error, of;
  
  
-       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+       of = dcaoflows[unit];
+       error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
+       /*
+        * XXX hardly a reasonable thing to do, but reporting overflows
+        * at interrupt time just exacerbates the problem.
+        */
+       if (dcaoflows[unit] != of)
+               log(LOG_WARNING, "dca%d: silo overflow\n", unit);
+       return (error);
 }
  
 dcawrite(dev, uio, flag)
        dev_t dev;
        struct uio *uio;
 }
  
 dcawrite(dev, uio, flag)
        dev_t dev;
        struct uio *uio;
+       int flag;
 {
        int unit = UNIT(dev);
        register struct tty *tp = &dca_tty[unit];
 {
        int unit = UNIT(dev);
        register struct tty *tp = &dca_tty[unit];
+       extern struct tty *constty;
  
        /*
         * (XXX) We disallow virtual consoles if the physical console is
  
        /*
         * (XXX) We disallow virtual consoles if the physical console is
@@ -227,44 +313,110 @@ dcaintr(unit)
        register int unit;
 {
        register struct dcadevice *dca;
        register int unit;
 {
        register struct dcadevice *dca;
-       register int code;
+       register u_char code;
+       register struct tty *tp;
+       int iflowdone = 0;
 
        dca = dca_addr[unit];
 
        dca = dca_addr[unit];
-       if ((dca->dca_ic & IC_IR) == 0)
-               return(0);
-       while (((code = dca->dca_iir) & IIR_NOPEND) == 0) {
-               code &= IIR_IMASK;
-               if (code == IIR_RLS)
-                       dcaeint(unit, dca);
-               else if (code == IIR_RXRDY)
-                       dcarint(unit, dca);
-               else if (code == IIR_TXRDY)
-                       dcaxint(unit, dca);
-               else
+#ifdef hp300
+       if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
+               return (0);
+#endif
+       tp = &dca_tty[unit];
+       while (1) {
+               code = dca->dca_iir;
+#ifdef DEBUG
+               dcaintrcount[code & IIR_IMASK]++;
+#endif
+               switch (code & IIR_IMASK) {
+               case IIR_NOPEND:
+                       return (1);
+               case IIR_RXTOUT:
+               case IIR_RXRDY:
+                       /* do time-critical read in-line */
+/*
+ * Process a received byte.  Inline for speed...
+ */
+#ifdef KGDB
+#define        RCVBYTE() \
+                       code = dca->dca_data; \
+                       if ((tp->t_state & TS_ISOPEN) == 0) { \
+                               if (code == FRAME_END && \
+                                   kgdb_dev == makedev(dcamajor, unit)) \
+                                       kgdb_connect(0); /* trap into kgdb */ \
+                       } else \
+                               (*linesw[tp->t_line].l_rint)(code, tp)
+#else
+#define        RCVBYTE() \
+                       code = dca->dca_data; \
+                       if ((tp->t_state & TS_ISOPEN) != 0) \
+                               (*linesw[tp->t_line].l_rint)(code, tp)
+#endif
+                       RCVBYTE();
+                       if (dca_hasfifo & (1 << unit)) {
+#ifdef DEBUG
+                               register int fifocnt = 1;
+#endif
+                               while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
+                                       if (code == LSR_RXRDY) {
+                                               RCVBYTE();
+                                       } else
+                                               dcaeint(unit, code, dca);
+#ifdef DEBUG
+                                       fifocnt++;
+#endif
+                               }
+#ifdef DEBUG
+                               if (fifocnt > 16)
+                                       fifoin[0]++;
+                               else
+                                       fifoin[fifocnt]++;
+#endif
+                       }
+                       if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
+                           tp->t_rawq.c_cc > TTYHOG/2) {
+                               dca->dca_mcr &= ~MCR_RTS;
+                               iflowdone = 1;
+                       }
+                       break;
+               case IIR_TXRDY:
+                       tp->t_state &=~ (TS_BUSY|TS_FLUSH);
+                       if (tp->t_line)
+                               (*linesw[tp->t_line].l_start)(tp);
+                       else
+                               dcastart(tp);
+                       break;
+               case IIR_RLS:
+                       dcaeint(unit, dca->dca_lsr, dca);
+                       break;
+               default:
+                       if (code & IIR_NOPEND)
+                               return (1);
+                       log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
+                           unit, code);
+                       /* fall through */
+               case IIR_MLSC:
                        dcamint(unit, dca);
                        dcamint(unit, dca);
+                       break;
+               }
        }
        }
-       return(1);
 }
 
 }
 
-dcaeint(unit, dca)
-       register int unit;
+dcaeint(unit, stat, dca)
+       register int unit, stat;
        register struct dcadevice *dca;
 {
        register struct tty *tp;
        register struct dcadevice *dca;
 {
        register struct tty *tp;
-       register int stat, c;
+       register int c;
 
        tp = &dca_tty[unit];
 
        tp = &dca_tty[unit];
-       stat = dca->dca_lsr;
-       c = dca->dca_data & 0xff;
+       c = dca->dca_data;
        if ((tp->t_state & TS_ISOPEN) == 0) {
 #ifdef KGDB
                /* we don't care about parity errors */
                if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
        if ((tp->t_state & TS_ISOPEN) == 0) {
 #ifdef KGDB
                /* we don't care about parity errors */
                if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
-                   kgdb_dev == makedev(1, unit) && c == '!') {
-                       printf("kgdb trap from dca%d\n", unit);
-                       /* trap into kgdb */
-                       asm("trap #15;");
-               }
+                   kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
+                       kgdb_connect(0); /* trap into kgdb */
 #endif
                return;
        }
 #endif
                return;
        }
@@ -273,69 +425,50 @@ dcaeint(unit, dca)
        else if (stat & LSR_PE)
                c |= TTY_PE;
        else if (stat & LSR_OE)
        else if (stat & LSR_PE)
                c |= TTY_PE;
        else if (stat & LSR_OE)
-               log(LOG_WARNING, "dca%d: silo overflow\n", unit);
-       (*linesw[tp->t_line].l_rint)(c, tp);
-}
-
-dcarint(unit, dca)
-       int unit;
-       register struct dcadevice *dca;
-{
-       register struct tty *tp;
-       register int c;
-
-       tp = &dca_tty[unit];
-       c = dca->dca_data;
-       if ((tp->t_state & TS_ISOPEN) == 0) {
-#ifdef KGDB
-               if (kgdb_dev == makedev(1, unit) && c == '!') {
-                       printf("kgdb trap from dca%d\n", unit);
-                       /* trap into kgdb */
-                       asm("trap #15;");
-               }
-#endif
-               return;
-       }
+               dcaoflows[unit]++;
        (*linesw[tp->t_line].l_rint)(c, tp);
 }
 
        (*linesw[tp->t_line].l_rint)(c, tp);
 }
 
-/*ARGSUSED*/
-dcaxint(unit, dca)
-       int unit;
-       struct dcadevice *dca;
-{
-       register struct tty *tp;
-
-       tp = &dca_tty[unit];
-       tp->t_state &= ~TS_BUSY;
-       if (tp->t_state & TS_FLUSH)
-               tp->t_state &= ~TS_FLUSH;
-       if (tp->t_line)
-               (*linesw[tp->t_line].l_start)(tp);
-       else
-               dcastart(tp);
-}
-
 dcamint(unit, dca)
        register int unit;
        register struct dcadevice *dca;
 {
        register struct tty *tp;
 dcamint(unit, dca)
        register int unit;
        register struct dcadevice *dca;
 {
        register struct tty *tp;
-       register int stat;
+       register u_char stat;
 
        tp = &dca_tty[unit];
        stat = dca->dca_msr;
 
        tp = &dca_tty[unit];
        stat = dca->dca_msr;
-       if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) {
+#ifdef DEBUG
+       dcamintcount[stat & 0xf]++;
+#endif
+       if ((stat & MSR_DDCD) &&
+           (dcasoftCAR & (1 << unit)) == 0) {
                if (stat & MSR_DCD)
                if (stat & MSR_DCD)
-                       (void) (*linesw[tp->t_line].l_modem)(tp, 1);
+                       (void)(*linesw[tp->t_line].l_modem)(tp, 1);
                else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
                        dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
        }
                else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
                        dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
        }
+       /*
+        * CTS change.
+        * If doing HW output flow control start/stop output as appropriate.
+        */
+       if ((stat & MSR_DCTS) &&
+           (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
+               if (stat & MSR_CTS) {
+                       tp->t_state &=~ TS_TTSTOP;
+                       dcastart(tp);
+               } else {
+                       tp->t_state |= TS_TTSTOP;
+               }
+       }
 }
 
 }
 
-dcaioctl(dev, cmd, data, flag)
+dcaioctl(dev, cmd, data, flag, p)
        dev_t dev;
        dev_t dev;
+       u_long cmd;
        caddr_t data;
        caddr_t data;
+       int flag;
+       struct proc *p;
 {
        register struct tty *tp;
        register int unit = UNIT(dev);
 {
        register struct tty *tp;
        register int unit = UNIT(dev);
@@ -343,7 +476,7 @@ dcaioctl(dev, cmd, data, flag)
        register int error;
  
        tp = &dca_tty[unit];
        register int error;
  
        tp = &dca_tty[unit];
-       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+       error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
        if (error >= 0)
                return (error);
        error = ttioctl(tp, cmd, data, flag);
        if (error >= 0)
                return (error);
        error = ttioctl(tp, cmd, data, flag);
@@ -402,7 +535,7 @@ dcaparam(tp, t)
  
        /* check requested parameters */
         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
  
        /* check requested parameters */
         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
-                return(EINVAL);
+                return (EINVAL);
         /* and copy to tty */
         tp->t_ispeed = t->c_ispeed;
         tp->t_ospeed = t->c_ospeed;
         /* and copy to tty */
         tp->t_ispeed = t->c_ispeed;
         tp->t_ospeed = t->c_ospeed;
@@ -410,9 +543,12 @@ dcaparam(tp, t)
 
        dca = dca_addr[unit];
        dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
 
        dca = dca_addr[unit];
        dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
+#ifdef hp700
+       dca->dca_mcr |= MCR_IEN;
+#endif
        if (ospeed == 0) {
                (void) dcamctl(unit, 0, DMSET); /* hang up line */
        if (ospeed == 0) {
                (void) dcamctl(unit, 0, DMSET); /* hang up line */
-               return(0);
+               return (0);
        }
        dca->dca_cfcr |= CFCR_DLAB;
        dca->dca_data = ospeed & 0xFF;
        }
        dca->dca_cfcr |= CFCR_DLAB;
        dca->dca_data = ospeed & 0xFF;
@@ -435,9 +571,12 @@ dcaparam(tp, t)
        if (cflag&CSTOPB)
                cfcr |= CFCR_STOPB;
        dca->dca_cfcr = cfcr;
        if (cflag&CSTOPB)
                cfcr |= CFCR_STOPB;
        dca->dca_cfcr = cfcr;
-       return(0);
+       if (dca_hasfifo & (1 << unit))
+               dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
+       return (0);
 }
  
 }
  
+void
 dcastart(tp)
        register struct tty *tp;
 {
 dcastart(tp)
        register struct tty *tp;
 {
@@ -447,24 +586,32 @@ dcastart(tp)
        unit = UNIT(tp->t_dev);
        dca = dca_addr[unit];
        s = spltty();
        unit = UNIT(tp->t_dev);
        dca = dca_addr[unit];
        s = spltty();
-       if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
+       if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
                goto out;
        if (tp->t_outq.c_cc <= tp->t_lowat) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
                        wakeup((caddr_t)&tp->t_outq);
                }
                goto out;
        if (tp->t_outq.c_cc <= tp->t_lowat) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
                        wakeup((caddr_t)&tp->t_outq);
                }
-               if (tp->t_wsel) {
-                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
-                       tp->t_wsel = 0;
-                       tp->t_state &= ~TS_WCOLL;
-               }
+               selwakeup(&tp->t_wsel);
        }
        if (tp->t_outq.c_cc == 0)
                goto out;
        }
        if (tp->t_outq.c_cc == 0)
                goto out;
-       c = getc(&tp->t_outq);
-       tp->t_state |= TS_BUSY;
-       dca->dca_data = c;
+       if (dca->dca_lsr & LSR_TXRDY) {
+               c = getc(&tp->t_outq);
+               tp->t_state |= TS_BUSY;
+               dca->dca_data = c;
+               if (dca_hasfifo & (1 << unit)) {
+                       for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
+                               dca->dca_data = getc(&tp->t_outq);
+#ifdef DEBUG
+                       if (c > 16)
+                               fifoout[0]++;
+                       else
+                               fifoout[c]++;
+#endif
+               }
+       }
 out:
        splx(s);
 }
 out:
        splx(s);
 }
@@ -475,6 +622,7 @@ out:
 /*ARGSUSED*/
 dcastop(tp, flag)
        register struct tty *tp;
 /*ARGSUSED*/
 dcastop(tp, flag)
        register struct tty *tp;
+       int flag;
 {
        register int s;
 
 {
        register int s;
 
@@ -496,6 +644,20 @@ dcamctl(dev, bits, how)
 
        unit = UNIT(dev);
        dca = dca_addr[unit];
 
        unit = UNIT(dev);
        dca = dca_addr[unit];
+#ifdef hp700
+       /*
+        * Always make sure MCR_IEN is set (unless setting to 0)
+        */
+#ifdef KGDB
+       if (how == DMSET && kgdb_dev == makedev(dcamajor, unit))
+               bits |= MCR_IEN;
+       else
+#endif
+       if (how == DMBIS || (how == DMSET && bits))
+               bits |= MCR_IEN;
+       else if (how == DMBIC)
+               bits &= ~MCR_IEN;
+#endif
        s = spltty();
        switch (how) {
 
        s = spltty();
        switch (how) {
 
@@ -516,39 +678,44 @@ dcamctl(dev, bits, how)
                break;
        }
        (void) splx(s);
                break;
        }
        (void) splx(s);
-       return(bits);
+       return (bits);
 }
 
 /*
  * Following are all routines needed for DCA to act as console
  */
 }
 
 /*
  * Following are all routines needed for DCA to act as console
  */
-#include "machine/cons.h"
+#include <hp/dev/cons.h>
 
 dcacnprobe(cp)
        struct consdev *cp;
 {
 
 dcacnprobe(cp)
        struct consdev *cp;
 {
-       int unit, i;
-       extern int dcaopen();
+       int unit;
+
+       /* locate the major number */
+       for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
+               if (cdevsw[dcamajor].d_open == dcaopen)
+                       break;
 
        /* XXX: ick */
        unit = CONUNIT;
 
        /* XXX: ick */
        unit = CONUNIT;
-       dca_addr[CONUNIT] = CONADDR;
+#ifdef hp300
+       dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
 
        /* make sure hardware exists */
        if (badaddr((short *)dca_addr[unit])) {
                cp->cn_pri = CN_DEAD;
                return;
        }
 
        /* make sure hardware exists */
        if (badaddr((short *)dca_addr[unit])) {
                cp->cn_pri = CN_DEAD;
                return;
        }
-
-       /* locate the major number */
-       for (i = 0; i < nchrdev; i++)
-               if (cdevsw[i].d_open == dcaopen)
-                       break;
+#endif
+#ifdef hp700
+       dca_addr[CONUNIT] = CONPORT;
+#endif
 
        /* initialize required fields */
 
        /* initialize required fields */
-       cp->cn_dev = makedev(i, unit);
+       cp->cn_dev = makedev(dcamajor, unit);
        cp->cn_tp = &dca_tty[unit];
        cp->cn_tp = &dca_tty[unit];
-       switch (dca_addr[unit]->dca_irid) {
+#ifdef hp300
+       switch (dca_addr[unit]->dca_id) {
        case DCAID0:
        case DCAID1:
                cp->cn_pri = CN_NORMAL;
        case DCAID0:
        case DCAID1:
                cp->cn_pri = CN_NORMAL;
@@ -561,6 +728,19 @@ dcacnprobe(cp)
                cp->cn_pri = CN_DEAD;
                break;
        }
                cp->cn_pri = CN_DEAD;
                break;
        }
+#endif
+#ifdef hp700
+       cp->cn_pri = CN_NORMAL;
+#endif
+       /*
+        * If dcaconsole is initialized, raise our priority.
+        */
+       if (dcaconsole == unit)
+               cp->cn_pri = CN_REMOTE;
+#ifdef KGDB
+       if (major(kgdb_dev) == 1)                       /* XXX */
+               kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
+#endif
 }
 
 dcacninit(cp)
 }
 
 dcacninit(cp)
@@ -568,15 +748,16 @@ dcacninit(cp)
 {
        int unit = UNIT(cp->cn_dev);
 
 {
        int unit = UNIT(cp->cn_dev);
 
-       dcainit(unit);
+       dcainit(unit, dcadefaultrate);
        dcaconsole = unit;
        dcaconsole = unit;
+       dcaconsinit = 1;
 }
 
 }
 
-dcainit(unit)
-       int unit;
+dcainit(unit, rate)
+       int unit, rate;
 {
        register struct dcadevice *dca;
 {
        register struct dcadevice *dca;
-       int s, rate;
+       int s;
        short stat;
 
 #ifdef lint
        short stat;
 
 #ifdef lint
@@ -584,27 +765,35 @@ dcainit(unit)
 #endif
        dca = dca_addr[unit];
        s = splhigh();
 #endif
        dca = dca_addr[unit];
        s = splhigh();
-       dca->dca_irid = 0xFF;
+#ifdef hp300
+       dca->dca_reset = 0xFF;
        DELAY(100);
        dca->dca_ic = IC_IE;
        DELAY(100);
        dca->dca_ic = IC_IE;
+#endif
        dca->dca_cfcr = CFCR_DLAB;
        dca->dca_cfcr = CFCR_DLAB;
-       rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
+       rate = ttspeedtab(rate, dcaspeedtab);
        dca->dca_data = rate & 0xFF;
        dca->dca_ier = rate >> 8;
        dca->dca_cfcr = CFCR_8BITS;
        dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
        dca->dca_data = rate & 0xFF;
        dca->dca_ier = rate >> 8;
        dca->dca_cfcr = CFCR_8BITS;
        dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
+#ifdef hp700
+       dca->dca_mcr |= MCR_IEN;
+#endif
+       dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
+       DELAY(100);
        stat = dca->dca_iir;
        splx(s);
 }
 
 dcacngetc(dev)
        stat = dca->dca_iir;
        splx(s);
 }
 
 dcacngetc(dev)
+       dev_t dev;
 {
        register struct dcadevice *dca = dca_addr[UNIT(dev)];
 {
        register struct dcadevice *dca = dca_addr[UNIT(dev)];
-       short stat;
+       register u_char stat;
        int c, s;
 
 #ifdef lint
        int c, s;
 
 #ifdef lint
-       stat = dev; if (stat) return(0);
+       stat = dev; if (stat) return (0);
 #endif
        s = splhigh();
        while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
 #endif
        s = splhigh();
        while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
@@ -612,7 +801,7 @@ dcacngetc(dev)
        c = dca->dca_data;
        stat = dca->dca_iir;
        splx(s);
        c = dca->dca_data;
        stat = dca->dca_iir;
        splx(s);
-       return(c);
+       return (c);
 }
 
 /*
 }
 
 /*
@@ -624,15 +813,15 @@ dcacnputc(dev, c)
 {
        register struct dcadevice *dca = dca_addr[UNIT(dev)];
        register int timo;
 {
        register struct dcadevice *dca = dca_addr[UNIT(dev)];
        register int timo;
-       short stat;
+       register u_char stat;
        int s = splhigh();
 
 #ifdef lint
        stat = dev; if (stat) return;
 #endif
        int s = splhigh();
 
 #ifdef lint
        stat = dev; if (stat) return;
 #endif
-       if (dcaconsole == -1) {
-               (void) dcainit(UNIT(dev));
-               dcaconsole = UNIT(dev);
+       if (dcaconsinit == 0) {
+               (void) dcainit(UNIT(dev), dcadefaultrate);
+               dcaconsinit = 1;
        }
        /* wait for any pending transmission to finish */
        timo = 50000;
        }
        /* wait for any pending transmission to finish */
        timo = 50000;
@@ -643,8 +832,13 @@ dcacnputc(dev, c)
        timo = 1500000;
        while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
                ;
        timo = 1500000;
        while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
                ;
-       /* clear any interrupts generated by this transmission */
-       stat = dca->dca_iir;
+       /*
+        * If the "normal" interface was busy transfering a character
+        * we must let our interrupt through to keep things moving.
+        * Otherwise, we clear the interrupt that we have caused.
+        */
+       if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0)
+               stat = dca->dca_iir;
        splx(s);
 }
 #endif
        splx(s);
 }
 #endif