strategy returns void, ioctl cmd is u_long
[unix-history] / usr / src / sys / hp / dev / dca.c
index 82667f0..1ee342c 100644 (file)
@@ -1,33 +1,45 @@
 /*
 /*
- * 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.13 (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
- *  uses National Semiconductor INS8250/NS16550AF UART
+ *  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 "sys/param.h"
-#include "sys/systm.h"
-#include "sys/ioctl.h"
-#include "sys/tty.h"
-#include "sys/proc.h"
-#include "sys/conf.h"
-#include "sys/file.h"
-#include "sys/uio.h"
-#include "sys/kernel.h"
-#include "sys/syslog.h"
-
-#include "device.h"
-#include "dcareg.h"
-#include "machine/cpu.h"
-#include "../hp300/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 = {
 
 int    dcaprobe();
 struct driver dcadriver = {
@@ -50,7 +62,11 @@ int  dcadefaultrate = TTYDEF_SPEED;
 int    dcamajor;
 struct dcadevice *dca_addr[NDCA];
 struct tty dca_tty[NDCA];
 int    dcamajor;
 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,
@@ -72,9 +88,8 @@ struct speedtab dcaspeedtab[] = {
        -1,     -1
 };
 
        -1,     -1
 };
 
-extern struct tty *constty;
 #ifdef KGDB
 #ifdef KGDB
-#include "machine/remote-sl.h"
+#include <machine/remote-sl.h>
 
 extern dev_t kgdb_dev;
 extern int kgdb_rate;
 
 extern dev_t kgdb_dev;
 extern int kgdb_rate;
@@ -97,16 +112,20 @@ 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);
        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;
 
        /* look for a NS 16550AF UART with FIFOs */
        dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
@@ -114,14 +133,17 @@ dcaprobe(hd)
        if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
                dca_hasfifo |= 1 << unit;
 
        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
        if (kgdb_dev == makedev(dcamajor, unit)) {
                if (dcaconsole == unit)
 #ifdef KGDB
        if (kgdb_dev == makedev(dcamajor, unit)) {
                if (dcaconsole == unit)
@@ -141,7 +163,9 @@ dcaprobe(hd)
                }
        }
 #endif
                }
        }
 #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 dcaconsinit.
         * 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."
@@ -202,6 +226,15 @@ dcaopen(dev, flag, mode, p)
        (void) spl0();
        if (error == 0)
                error = (*linesw[tp->t_line].l_open)(dev, tp);
        (void) spl0();
        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);
 }
  
        return (error);
 }
  
@@ -216,6 +249,10 @@ dcaclose(dev, flag, mode, p)
        register int unit;
  
        unit = UNIT(dev);
        register int unit;
  
        unit = UNIT(dev);
+#ifdef hp300
+       if (unit == 0)
+               dcafastservice = 0;
+#endif
        dca = dca_addr[unit];
        tp = &dca_tty[unit];
        (*linesw[tp->t_line].l_close)(tp, flag);
        dca = dca_addr[unit];
        tp = &dca_tty[unit];
        (*linesw[tp->t_line].l_close)(tp, flag);
@@ -235,18 +272,31 @@ dcaclose(dev, flag, mode, p)
 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
@@ -265,10 +315,14 @@ dcaintr(unit)
        register struct dcadevice *dca;
        register u_char code;
        register struct tty *tp;
        register struct dcadevice *dca;
        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)
+#ifdef hp300
+       if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
                return (0);
                return (0);
+#endif
+       tp = &dca_tty[unit];
        while (1) {
                code = dca->dca_iir;
 #ifdef DEBUG
        while (1) {
                code = dca->dca_iir;
 #ifdef DEBUG
@@ -280,7 +334,6 @@ dcaintr(unit)
                case IIR_RXTOUT:
                case IIR_RXRDY:
                        /* do time-critical read in-line */
                case IIR_RXTOUT:
                case IIR_RXRDY:
                        /* do time-critical read in-line */
-                       tp = &dca_tty[unit];
 /*
  * Process a received byte.  Inline for speed...
  */
 /*
  * Process a received byte.  Inline for speed...
  */
@@ -320,9 +373,13 @@ dcaintr(unit)
                                        fifoin[fifocnt]++;
 #endif
                        }
                                        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:
                        break;
                case IIR_TXRDY:
-                       tp = &dca_tty[unit];
                        tp->t_state &=~ (TS_BUSY|TS_FLUSH);
                        if (tp->t_line)
                                (*linesw[tp->t_line].l_start)(tp);
                        tp->t_state &=~ (TS_BUSY|TS_FLUSH);
                        if (tp->t_line)
                                (*linesw[tp->t_line].l_start)(tp);
@@ -368,7 +425,7 @@ dcaeint(unit, stat, 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);
+               dcaoflows[unit]++;
        (*linesw[tp->t_line].l_rint)(c, tp);
 }
 
        (*linesw[tp->t_line].l_rint)(c, tp);
 }
 
@@ -377,32 +434,41 @@ dcamint(unit, dca)
        register struct dcadevice *dca;
 {
        register struct tty *tp;
        register struct dcadevice *dca;
 {
        register struct tty *tp;
-       register int stat;
+       register u_char stat;
 
        tp = &dca_tty[unit];
        stat = dca->dca_msr;
 #ifdef DEBUG
        dcamintcount[stat & 0xf]++;
 #endif
 
        tp = &dca_tty[unit];
        stat = dca->dca_msr;
 #ifdef DEBUG
        dcamintcount[stat & 0xf]++;
 #endif
-       if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
+       if ((stat & MSR_DDCD) &&
+           (dcasoftCAR & (1 << unit)) == 0) {
                if (stat & MSR_DCD)
                        (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);
                if (stat & MSR_DCD)
                        (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 ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
-                  (tp->t_flags & CRTSCTS)) {
-               /* the line is up and we want to do rts/cts flow control */
+       }
+       /*
+        * 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;
                if (stat & MSR_CTS) {
                        tp->t_state &=~ TS_TTSTOP;
-                       ttstart(tp);
-               } else
+                       dcastart(tp);
+               } else {
                        tp->t_state |= TS_TTSTOP;
                        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);
@@ -410,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);
@@ -477,6 +543,9 @@ 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 */
                return (0);
        if (ospeed == 0) {
                (void) dcamctl(unit, 0, DMSET); /* hang up line */
                return (0);
@@ -524,11 +593,7 @@ dcastart(tp)
                        tp->t_state &= ~TS_ASLEEP;
                        wakeup((caddr_t)&tp->t_outq);
                }
                        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;
@@ -557,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;
 
@@ -578,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) {
 
@@ -604,7 +684,7 @@ dcamctl(dev, bits, how)
 /*
  * Following are all routines needed for DCA to act as console
  */
 /*
  * Following are all routines needed for DCA to act as console
  */
-#include "../hp300/cons.h"
+#include <hp/dev/cons.h>
 
 dcacnprobe(cp)
        struct consdev *cp;
 
 dcacnprobe(cp)
        struct consdev *cp;
@@ -618,6 +698,7 @@ dcacnprobe(cp)
 
        /* XXX: ick */
        unit = CONUNIT;
 
        /* XXX: ick */
        unit = CONUNIT;
+#ifdef hp300
        dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
 
        /* make sure hardware exists */
        dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
 
        /* make sure hardware exists */
@@ -625,11 +706,16 @@ dcacnprobe(cp)
                cp->cn_pri = CN_DEAD;
                return;
        }
                cp->cn_pri = CN_DEAD;
                return;
        }
+#endif
+#ifdef hp700
+       dca_addr[CONUNIT] = CONPORT;
+#endif
 
        /* initialize required fields */
        cp->cn_dev = makedev(dcamajor, unit);
        cp->cn_tp = &dca_tty[unit];
 
        /* initialize required fields */
        cp->cn_dev = makedev(dcamajor, 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;
@@ -642,6 +728,10 @@ 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 is initialized, raise our priority.
         */
@@ -675,24 +765,31 @@ dcainit(unit, rate)
 #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;
        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_cfcr = CFCR_DLAB;
        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;
+#ifdef hp700
+       dca->dca_mcr |= MCR_IEN;
+#endif
        dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
        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
@@ -716,7 +813,7 @@ 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
        int s = splhigh();
 
 #ifdef lint
@@ -735,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