New sio driver from Bruce.
authorAndrey Chernov <ache@FreeBSD.org>
Sun, 14 Nov 1993 23:29:50 +0000 (23:29 +0000)
committerAndrey Chernov <ache@FreeBSD.org>
Sun, 14 Nov 1993 23:29:50 +0000 (23:29 +0000)
sys/i386/isa/sio.c
sys/kern/tty.c
sys/sys/ioctl.h
sys/sys/tty.h

index 3dc4e2d..0e43187 100644 (file)
  * SUCH DAMAGE.
  *
  *     from: @(#)com.c 7.5 (Berkeley) 5/16/91
  * SUCH DAMAGE.
  *
  *     from: @(#)com.c 7.5 (Berkeley) 5/16/91
- *     $Id: sio.c,v 1.12 1993/10/16 13:46:18 rgrimes Exp $
+ *     $Id: sio.c,v 1.13 1993/11/08 19:36:32 ache Exp $
  */
 
 #include "sio.h"
 #if NSIO > 0
 /*
  */
 
 #include "sio.h"
 #if NSIO > 0
 /*
- * COM driver, based on HP dca driver.
+ * Serial driver, based on 386BSD-0.1 com driver.
  * Mostly rewritten to use pseudo-DMA.
  * Works for National Semiconductor NS8250-NS16550AF UARTs.
  * Mostly rewritten to use pseudo-DMA.
  * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
  */
 #include "param.h"
 #include "systm.h"
  */
 #include "param.h"
 #include "systm.h"
 #include "i386/isa/comreg.h"
 #include "i386/isa/ic/ns16550.h"
 
 #include "i386/isa/comreg.h"
 #include "i386/isa/ic/ns16550.h"
 
-#undef CRTS_IFLOW
-#define        CRTS_IFLOW      CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */
+#define FAKE_DCD(unit) ((unit) == comconsole)
 #define        LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
 #define        RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
 #define        RB_I_LOW_WATER  ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
 #define        RS_IBUFSIZE     256
 #define        LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
 #define        RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
 #define        RB_I_LOW_WATER  ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
 #define        RS_IBUFSIZE     256
-#define        TS_RTSBLOCK     TS_TBLOCK       /* XXX */
 #define        TTY_BI          TTY_FE          /* XXX */
 #define        TTY_OE          TTY_PE          /* XXX */
 #define        TTY_BI          TTY_FE          /* XXX */
 #define        TTY_OE          TTY_PE          /* XXX */
+
 #ifndef COM_BIDIR
 #define        UNIT(x)         (minor(x))      /* XXX */
 #else /* COM_BIDIR */
 #define COM_UNITMASK    0x7f
 #define COM_CALLOUTMASK 0x80
 #ifndef COM_BIDIR
 #define        UNIT(x)         (minor(x))      /* XXX */
 #else /* COM_BIDIR */
 #define COM_UNITMASK    0x7f
 #define COM_CALLOUTMASK 0x80
-
 #define UNIT(x)         (minor(x) & COM_UNITMASK)
 #define CALLOUT(x)      (minor(x) & COM_CALLOUTMASK)
 #endif /* COM_BIDIR */
 #define UNIT(x)         (minor(x) & COM_UNITMASK)
 #define CALLOUT(x)      (minor(x) & COM_CALLOUTMASK)
 #endif /* COM_BIDIR */
@@ -145,7 +144,6 @@ struct com_s {
        u_char  cfcr_image;     /* copy of value written to CFCR */
        bool_t  hasfifo;        /* nonzero for 16550 UARTs */
        u_char  mcr_image;      /* copy of value written to MCR */
        u_char  cfcr_image;     /* copy of value written to CFCR */
        bool_t  hasfifo;        /* nonzero for 16550 UARTs */
        u_char  mcr_image;      /* copy of value written to MCR */
-       bool_t  softDCD;        /* nonzero for faked carrier detect */
 #ifdef COM_BIDIR
        bool_t  bidir;          /* is this unit bidirectional? */
        bool_t  active;         /* is the port active _at all_? */
 #ifdef COM_BIDIR
        bool_t  bidir;          /* is this unit bidirectional? */
        bool_t  active;         /* is the port active _at all_? */
@@ -155,6 +153,7 @@ struct com_s {
 #ifdef COM_MULTIPORT
        bool_t  multiport;      /* is this unit part of a multiport device? */
 #endif /* COM_MULTIPORT */
 #ifdef COM_MULTIPORT
        bool_t  multiport;      /* is this unit part of a multiport device? */
 #endif /* COM_MULTIPORT */
+       int     dtr_wait;       /* time to hold DTR down on close (* 1/HZ) */
 
        /*
         * The high level of the driver never reads status registers directly
 
        /*
         * The high level of the driver never reads status registers directly
@@ -197,6 +196,12 @@ struct com_s {
        u_char  ibuf2[2 * RS_IBUFSIZE];
 };
 
        u_char  ibuf2[2 * RS_IBUFSIZE];
 };
 
+/* XXX - these functions ought to be declared in systm.h. */
+#define        nonint  int
+nonint timeout         __P((timeout_func_t func, caddr_t arg, int t));
+int    tsleep          __P((caddr_t chan, int pri, char *wmesg, int timo));
+int    ttnread         __P((struct tty *tp));
+nonint wakeup          __P((caddr_t chan));
 
 /*
  * These functions in the com module ought to be declared (with a prototype)
 
 /*
  * These functions in the com module ought to be declared (with a prototype)
@@ -209,9 +214,6 @@ struct consdev;
 int    sioclose        __P((Dev_t dev, int fflag, int devtype,
                             struct proc *p));
 void   siointr         __P((int unit));
 int    sioclose        __P((Dev_t dev, int fflag, int devtype,
                             struct proc *p));
 void   siointr         __P((int unit));
-#ifdef COM_MULTIPORT
-bool_t comintr1        __P((struct com_s *com));
-#endif /* COM_MULTIPORT */
 int    sioioctl        __P((Dev_t dev, int cmd, caddr_t data,
                             int fflag, struct proc *p));
 int    siocngetc       __P((Dev_t dev));
 int    sioioctl        __P((Dev_t dev, int cmd, caddr_t data,
                             int fflag, struct proc *p));
 int    siocngetc       __P((Dev_t dev));
@@ -239,29 +241,25 @@ int       sioopen         __P((Dev_t dev, int oflags, int devtype,
 typedef        int     (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
                                     struct proc *p));
 int    sioread         __P((Dev_t dev, struct uio *uio, int ioflag));
 typedef        int     (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
                                     struct proc *p));
 int    sioread         __P((Dev_t dev, struct uio *uio, int ioflag));
+int    sioselect       __P((Dev_t dev, int rw, struct proc *p));
 void   siostop         __P((struct tty *tp, int rw));
 int    siowrite        __P((Dev_t dev, struct uio *uio, int ioflag));
 void   siostop         __P((struct tty *tp, int rw));
 int    siowrite        __P((Dev_t dev, struct uio *uio, int ioflag));
-void   softsio0        __P((void));
 void   softsio1        __P((void));
 void   softsio1        __P((void));
-void   softsio2        __P((void));
-void   softsio3        __P((void));
-void   softsio4        __P((void));
-void   softsio5        __P((void));
-void   softsio6        __P((void));
-void   softsio7        __P((void));
-void   softsio8        __P((void));
 
 static int     sioattach       __P((struct isa_device *dev));
 static void    comflush        __P((struct com_s *com));
 static void    comhardclose    __P((struct com_s *com));
 static void    cominit         __P((int unit, int rate));
 
 static int     sioattach       __P((struct isa_device *dev));
 static void    comflush        __P((struct com_s *com));
 static void    comhardclose    __P((struct com_s *com));
 static void    cominit         __P((int unit, int rate));
+#ifdef COM_MULTIPORT
+static bool_t  comintr1        __P((struct com_s *com));
+#endif /* COM_MULTIPORT */
 static int     commctl         __P((struct com_s *com, int bits, int how));
 static int     comparam        __P((struct tty *tp, struct termios *t));
 static int     sioprobe        __P((struct isa_device *dev));
 static void    compoll         __P((void));
 static int     comstart        __P((struct tty *tp));
 static int     commctl         __P((struct com_s *com, int bits, int how));
 static int     comparam        __P((struct tty *tp, struct termios *t));
 static int     sioprobe        __P((struct isa_device *dev));
 static void    compoll         __P((void));
 static int     comstart        __P((struct tty *tp));
-static void    comwakeup       __P((void));
-static int     tiocm2mcr       __P((int));
+static nonint  comwakeup       __P((caddr_t chan, int ticks));
+static int     tiocm_xxx2mcr   __P((int tiocm_xxx));
 
 /* table and macro for fast conversion from a unit number to its com struct */
 static struct com_s    *p_com_addr[NSIO];
 
 /* table and macro for fast conversion from a unit number to its com struct */
 static struct com_s    *p_com_addr[NSIO];
@@ -344,7 +342,7 @@ sioprobe(dev)
                already_init = TRUE;
        }
        iobase = dev->id_iobase;
                already_init = TRUE;
        }
        iobase = dev->id_iobase;
-       result = IO_COMSIZE;
+       result = 1;
 
        /*
         * We don't want to get actual interrupts, just masked ones.
 
        /*
         * We don't want to get actual interrupts, just masked ones.
@@ -369,6 +367,9 @@ sioprobe(dev)
        if (   inb(iobase + com_cfcr) != CFCR_8BITS
            || inb(iobase + com_ier) != IER_ETXRDY
            || inb(iobase + com_mcr) != MCR_IENABLE
        if (   inb(iobase + com_cfcr) != CFCR_8BITS
            || inb(iobase + com_ier) != IER_ETXRDY
            || inb(iobase + com_mcr) != MCR_IENABLE
+#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
+           || !isa_irq_pending(dev)
+#endif
            || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
            || isa_irq_pending(dev)
            || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
            || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
            || isa_irq_pending(dev)
            || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
@@ -390,7 +391,6 @@ sioprobe(dev)
                result = 0;
 
        enable_intr();
                result = 0;
 
        enable_intr();
-
        return (result);
 }
 
        return (result);
 }
 
@@ -402,9 +402,6 @@ sioattach(isdp)
        static bool_t   comwakeup_started = FALSE;
        Port_t          iobase;
        int             s;
        static bool_t   comwakeup_started = FALSE;
        Port_t          iobase;
        int             s;
-       u_char          scr;
-       u_char          scr1;
-       u_char          scr2;
        int             unit;
 
        iobase = isdp->id_iobase;
        int             unit;
 
        iobase = isdp->id_iobase;
@@ -428,9 +425,7 @@ sioattach(isdp)
        com = &com_structs[unit];
        com->cfcr_image = CFCR_8BITS;
        com->mcr_image = MCR_IENABLE;
        com = &com_structs[unit];
        com->cfcr_image = CFCR_8BITS;
        com->mcr_image = MCR_IENABLE;
-#if 0
-       com->softDCD = TRUE;
-#endif
+       com->dtr_wait = 50;
        com->iptr = com->ibuf = com->ibuf1;
        com->ibufend = com->ibuf1 + RS_IBUFSIZE;
        com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
        com->iptr = com->ibuf = com->ibuf1;
        com->ibufend = com->ibuf1 + RS_IBUFSIZE;
        com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
@@ -451,39 +446,45 @@ sioattach(isdp)
 #endif /* COM_BIDIR */
 
        /* attempt to determine UART type */
 #endif /* COM_BIDIR */
 
        /* attempt to determine UART type */
-       scr = inb(iobase + com_scr);
-       outb(iobase + com_scr, 0xa5);
-       scr1 = inb(iobase + com_scr);
-       outb(iobase + com_scr, 0x5a);
-       scr2 = inb(iobase + com_scr);
-       outb(iobase + com_scr, scr);
-       printf("sio%d: type", unit);
 #ifdef COM_MULTIPORT
 #ifdef COM_MULTIPORT
-       if (0);
-#else
-       if (scr1 != 0xa5 || scr2 != 0x5a)
-               printf(" <8250>");
+       if (!COM_ISMULTIPORT(isdp))
 #endif
 #endif
-       else {
-               outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
-               DELAY(100);
-               switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
-               case FIFO_TRIGGER_1:
-                       printf(" <16450>");
-                       break;
-               case FIFO_TRIGGER_4:
-                       printf(" <16450?>");
-                       break;
-               case FIFO_TRIGGER_8:
-                       printf(" <16550?>");
-                       break;
-               case FIFO_TRIGGER_14:
-                       com->hasfifo = TRUE;
-                       printf(" <16550A>");
-                       break;
+       {
+               u_char  scr;
+               u_char  scr1;
+               u_char  scr2;
+
+               scr = inb(iobase + com_scr);
+               outb(iobase + com_scr, 0xa5);
+               scr1 = inb(iobase + com_scr);
+               outb(iobase + com_scr, 0x5a);
+               scr2 = inb(iobase + com_scr);
+               outb(iobase + com_scr, scr);
+               if (scr1 != 0xa5 || scr2 != 0x5a) {
+                       printf(" <8250>");
+                       goto determined_type;
                }
                }
-               outb(iobase + com_fifo, 0);
        }
        }
+       outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+       DELAY(100);
+       switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
+       case FIFO_TRIGGER_1:
+               printf(" <16450>");
+               break;
+       case FIFO_TRIGGER_4:
+               printf(" <16450?>");
+               break;
+       case FIFO_TRIGGER_8:
+               printf(" <16550?>");
+               break;
+       case FIFO_TRIGGER_14:
+               com->hasfifo = TRUE;
+               printf(" <16550A>");
+               break;
+       }
+       outb(iobase + com_fifo, 0);
+determined_type: ;
+
 #ifdef COM_MULTIPORT
        if (COM_ISMULTIPORT(isdp)) {
                struct isa_device *masterdev;
 #ifdef COM_MULTIPORT
        if (COM_ISMULTIPORT(isdp)) {
                struct isa_device *masterdev;
@@ -504,7 +505,6 @@ sioattach(isdp)
        else
                com->multiport = FALSE;
 #endif /* COM_MULTIPORT */
        else
                com->multiport = FALSE;
 #endif /* COM_MULTIPORT */
-       printf("\n");
 
 #ifdef KGDB
        if (kgdb_dev == makedev(commajor, unit)) {
 
 #ifdef KGDB
        if (kgdb_dev == makedev(commajor, unit)) {
@@ -517,11 +517,11 @@ sioattach(isdp)
                                 * Print prefix of device name,
                                 * let kgdb_connect print the rest.
                                 */
                                 * Print prefix of device name,
                                 * let kgdb_connect print the rest.
                                 */
-                               printf("com%d: ", unit);
+                               printf("sio%d: ", unit);
                                kgdb_connect(1);
                        }
                        else
                                kgdb_connect(1);
                        }
                        else
-                               printf("com%d: kgdb enabled\n", unit);
+                               printf("sio%d: kgdb enabled\n", unit);
                }
        }
 #endif
                }
        }
 #endif
@@ -530,17 +530,15 @@ sioattach(isdp)
         * Need to reset baud rate, etc. of next print so reset comconsinit.
         * Also make sure console is always "hardwired"
         */
         * Need to reset baud rate, etc. of next print so reset comconsinit.
         * Also make sure console is always "hardwired"
         */
-       if (unit == comconsole) {
+       if (unit == comconsole)
                comconsinit = FALSE;
                comconsinit = FALSE;
-               com->softDCD = TRUE;
-       }
 
        com_addr(unit) = com;
 
        splx(s);
 
        if (!comwakeup_started) {
 
        com_addr(unit) = com;
 
        splx(s);
 
        if (!comwakeup_started) {
-               comwakeup();
+               comwakeup((caddr_t) NULL, 0);
                comwakeup_started = TRUE;
        }
 
                comwakeup_started = TRUE;
        }
 
@@ -588,7 +586,6 @@ bidir_open_top:
                        } else {
                            /* it's ours.  lock it down, and set it up */
                            com->active_out = TRUE;
                        } else {
                            /* it's ours.  lock it down, and set it up */
                            com->active_out = TRUE;
-                           com->softDCD = TRUE;
                        }
                } else {
                        if (com->active_out) {
                        }
                } else {
                        if (com->active_out) {
@@ -599,9 +596,9 @@ bidir_open_top:
                                    return (EBUSY);
                                } else {
                                    /* wait for it... */
                                    return (EBUSY);
                                } else {
                                    /* wait for it... */
-                                   error = tsleep(&com->active_out,
+                                   error = tsleep((caddr_t)&com->active_out,
                                                   TTIPRI|PCATCH,
                                                   TTIPRI|PCATCH,
-                                                  "comoth",
+                                                  "siooth",
                                                   0);
                                    /* if there was an error, take off. */
                                    if (error != 0) {
                                                   0);
                                    /* if there was an error, take off. */
                                    if (error != 0) {
@@ -611,31 +608,31 @@ bidir_open_top:
                                    /* else take it from the top */
                                    goto bidir_open_top;
                                }
                                    /* else take it from the top */
                                    goto bidir_open_top;
                                }
-                       } else if (com->last_modem_status & MSR_DCD) {
+                       } else if (com->prev_modem_status & MSR_DCD
+                                  || FAKE_DCD(unit)) {
                                /* there's a carrier on the line; we win */
                                com->active_in = TRUE;
                                /* there's a carrier on the line; we win */
                                com->active_in = TRUE;
-                               com->softDCD = FALSE;
                        } else {
                                /* there is no carrier on the line */
                                if (flag & O_NONBLOCK) {
                                    /* can't wait; let it open */
                                    com->active_in = TRUE;
                        } else {
                                /* there is no carrier on the line */
                                if (flag & O_NONBLOCK) {
                                    /* can't wait; let it open */
                                    com->active_in = TRUE;
-                                   com->softDCD = FALSE;
                                } else {
                                    /* put DTR & RTS up */
                                    /* NOTE: cgd'sdriver used the ier register
                                     * to enable/disable interrupts. This one
                                     * uses both ier and IENABLE in the mcr.
                                     */
                                } else {
                                    /* put DTR & RTS up */
                                    /* NOTE: cgd'sdriver used the ier register
                                     * to enable/disable interrupts. This one
                                     * uses both ier and IENABLE in the mcr.
                                     */
+                                   /* XXX - bring up RTS earlier? */
                                    (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
                                    outb(com->iobase + com_ier, IER_EMSC);
                                    /* wait for it... */
                                    (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
                                    outb(com->iobase + com_ier, IER_EMSC);
                                    /* wait for it... */
-                                   error = tsleep(&com->active_in,
+                                   error = tsleep((caddr_t)&com->active_in,
                                                   TTIPRI|PCATCH,
                                                   TTIPRI|PCATCH,
-                                                  "comdcd",
+                                                  "siodcd",
                                                   0);
 
                                                   0);
 
-                                   /* if not active, turn DTR & RTS off */
+                                   /* if not active, turn DTR off */
                                    if (!com->active)
                                        (void) commctl(com, MCR_DTR, DMBIC);
 
                                    if (!com->active)
                                        (void) commctl(com, MCR_DTR, DMBIC);
 
@@ -666,11 +663,19 @@ bidir_open_top:
                         * since those are only relevant for logins.  It's
                         * important to have echo off initially so that the
                         * line doesn't start blathering before the echo flag
                         * since those are only relevant for logins.  It's
                         * important to have echo off initially so that the
                         * line doesn't start blathering before the echo flag
-                        * can be turned off.
+                        * can be turned off.  It's useful to have clocal on
+                        * initially so that "stty changed-defaults </dev/sioX"
+                        * doesn't hang waiting for carrier.
+                        *
+                        * XXX: CLOCAL is dangerous with incoming ports:
+                        * it cause getty hangs after first login+logout.
+                        * use "stty com_speed -clocal < /dev/comxx"
+                        * before do anything with incoming port...
+                        *                                   Ache.
                         */
                        tp->t_iflag = 0;
                        tp->t_oflag = 0;
                         */
                        tp->t_iflag = 0;
                        tp->t_oflag = 0;
-                       tp->t_cflag = CREAD | CS8 | HUPCL;
+                       tp->t_cflag = CREAD | CS8 | CLOCAL;
                        tp->t_lflag = 0;
                        tp->t_ispeed = tp->t_ospeed = comdefaultrate;
                }
                        tp->t_lflag = 0;
                        tp->t_ispeed = tp->t_ospeed = comdefaultrate;
                }
@@ -692,7 +697,7 @@ bidir_open_top:
                outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
                                       | IER_EMSC);
                enable_intr();
                outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
                                       | IER_EMSC);
                enable_intr();
-               if (com->softDCD || com->prev_modem_status & MSR_DCD)
+               if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
                        tp->t_state |= TS_CARR_ON;
        }
        else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
                        tp->t_state |= TS_CARR_ON;
        }
        else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
@@ -726,16 +731,14 @@ out:
 
        /*
         * XXX - the next step was once not done, so interrupts, DTR and RTS
 
        /*
         * XXX - the next step was once not done, so interrupts, DTR and RTS
-        * remainded hot if the process was killed while it was sleeping
+        * remained hot if the process was killed while it was sleeping
         * waiting for carrier.  Now there is the opposite problem.  If several
         * processes are sleeping waiting for carrier on the same line and one
         * is killed, interrupts are turned off so the other processes will
         * never see the carrier rise.
         */
        if (error != 0 && !(tp->t_state & TS_ISOPEN))
         * waiting for carrier.  Now there is the opposite problem.  If several
         * processes are sleeping waiting for carrier on the same line and one
         * is killed, interrupts are turned off so the other processes will
         * never see the carrier rise.
         */
        if (error != 0 && !(tp->t_state & TS_ISOPEN))
-{
                comhardclose(com);
                comhardclose(com);
-}
        tp->t_state &= ~TS_WOPEN;
 
        return (error);
        tp->t_state &= ~TS_WOPEN;
 
        return (error);
@@ -760,7 +763,7 @@ sioclose(dev, flag, mode, p)
        return (0);
 }
 
        return (0);
 }
 
-void
+static void
 comhardclose(com)
        struct com_s    *com;
 {
 comhardclose(com)
        struct com_s    *com;
 {
@@ -778,11 +781,16 @@ comhardclose(com)
                outb(iobase + com_ier, 0);
        tp = com->tp;
        if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
                outb(iobase + com_ier, 0);
        tp = com->tp;
        if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
-           || !(tp->t_state & TS_ISOPEN))
+           || !(tp->t_state & TS_ISOPEN)) {
                (void) commctl(com, MCR_RTS, DMSET);
                (void) commctl(com, MCR_RTS, DMSET);
+               if (com->dtr_wait != 0)
+                       /* uninterruptible since we want to wait a fixed time */
+                       tsleep((caddr_t)&com->dtr_wait, TTIPRI, "sioclose",
+                              com->dtr_wait);
+       }
+
 #ifdef COM_BIDIR
        com->active = com->active_in = com->active_out = FALSE;
 #ifdef COM_BIDIR
        com->active = com->active_in = com->active_out = FALSE;
-       com->softDCD = FALSE;
 
        /* wakeup sleepers who are waiting for out to finish */
        wakeup((caddr_t) &com->active_out);
 
        /* wakeup sleepers who are waiting for out to finish */
        wakeup((caddr_t) &com->active_out);
@@ -838,29 +846,38 @@ siointr(unit)
        int             i;
        bool_t          donesomething;
 
        int             i;
        bool_t          donesomething;
 
+       /*
+        * Loop until there is no activity on any port.  This is necessary
+        * to get an interrupt edge more than to avoid another interrupt.
+        * If the IRQ signal is just an OR of the IRQ signals from several
+        * devices, then the edge from one may be lost because another is
+        * on, or it may cause a stray interrupt because another was on a
+        * short time before.
+        *
+        * XXX getting the status from comintr1() is not best and may be
+        * incorrect.  It would be better to test the int_id's in a tight
+        * loop.  If each is off when it is tested, then they all must
+        * have been off at the start.
+        */
        do {
                donesomething = FALSE;
                for(i=0;i<NSIO;i++) {
                        com=com_addr(i);
                        if(com != NULL) {
        do {
                donesomething = FALSE;
                for(i=0;i<NSIO;i++) {
                        com=com_addr(i);
                        if(com != NULL) {
-                               /* XXX When siointr is called
-                                * to start output, maybe
-                                * it should be changed to a
-                                * call to comintr1. Doesn't
-                                * seem a good idea: interrupts
-                                * are disabled all the time.
+                               /* XXX call comintr1() instead of here from
+                                * com_wakeup().  The interrupt edge problem
+                                * only exists for real interrupts.
                                 */
                                 */
-enable_intr();
-disable_intr();
-                               donesomething = comintr1(com);
+                               donesomething |= comintr1(com);
                        }
                }
        } while (donesomething);
        return;
 }
                        }
                }
        } while (donesomething);
        return;
 }
-       
-bool_t
-comintr1(struct com_s *com)
+
+static bool_t
+comintr1(com)
+       struct com_s *com;
 {
        u_char          line_status;
        u_char          modem_status;
 {
        u_char          line_status;
        u_char          modem_status;
@@ -906,6 +923,9 @@ comintr1(struct com_s *com)
                                    && com->state & CS_RTS_IFLOW)
                                        outb(com->modem_ctl_port,
                                             com->mcr_image &= ~MCR_RTS);
                                    && com->state & CS_RTS_IFLOW)
                                        outb(com->modem_ctl_port,
                                             com->mcr_image &= ~MCR_RTS);
+                               /* XXX - move this out of isr */
+                               if (line_status & LSR_OE)
+                                       CE_RECORD(com, CE_OVERRUN);
                        }
 
                        /*
                        }
 
                        /*
@@ -972,14 +992,19 @@ comintr1(struct com_s *com)
 }
 
 static int
 }
 
 static int
-tiocm2mcr(data)
-       int data;
+tiocm_xxx2mcr(tiocm_xxx)
+       int tiocm_xxx;
 {
 {
-       register m = 0;
-       if (data & TIOCM_DTR) m |= MCR_DTR;
-       if (data & TIOCM_RTS) m |= MCR_RTS;
-       return m;
+       int mcr;
+
+       mcr = 0;
+       if (tiocm_xxx & TIOCM_DTR)
+               mcr |= MCR_DTR;
+       if (tiocm_xxx & TIOCM_RTS)
+               mcr |= MCR_RTS;
+       return (mcr);
 }
 }
+
 int
 sioioctl(dev, cmd, data, flag, p)
        dev_t           dev;
 int
 sioioctl(dev, cmd, data, flag, p)
        dev_t           dev;
@@ -991,7 +1016,10 @@ sioioctl(dev, cmd, data, flag, p)
        struct com_s    *com;
        int             error;
        Port_t          iobase;
        struct com_s    *com;
        int             error;
        Port_t          iobase;
+       int             mcr;
+       int             msr;
        int             s;
        int             s;
+       int             tiocm_xxx;
        struct tty      *tp;
 
        com = com_addr(UNIT(dev));
        struct tty      *tp;
 
        com = com_addr(UNIT(dev));
@@ -1019,28 +1047,32 @@ sioioctl(dev, cmd, data, flag, p)
                (void) commctl(com, MCR_DTR, DMBIC);
                break;
        case TIOCMSET:
                (void) commctl(com, MCR_DTR, DMBIC);
                break;
        case TIOCMSET:
-               (void) commctl(com, tiocm2mcr(*(int *)data), DMSET);
+               (void) commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
                break;
        case TIOCMBIS:
                break;
        case TIOCMBIS:
-               (void) commctl(com, tiocm2mcr(*(int *)data), DMBIS);
+               (void) commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
                break;
        case TIOCMBIC:
                break;
        case TIOCMBIC:
-               (void) commctl(com, tiocm2mcr(*(int *)data), DMBIC);
+               (void) commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
                break;
        case TIOCMGET:
                break;
        case TIOCMGET:
-               {
-                       register int bits = 0, mode;
-
-                       mode = commctl(com, 0, DMGET);
-                       if (inb(com->iobase+com_ier)) bits |= TIOCM_LE; /* XXX */
-                       if (mode & MSR_DCD) bits |= TIOCM_CD;
-                       if (mode & MSR_CTS) bits |= TIOCM_CTS;
-                       if (mode & MSR_DSR) bits |= TIOCM_DSR;
-                       if (mode & (MCR_DTR<<8)) bits |= TIOCM_DTR;
-                       if (mode & (MCR_RTS<<8)) bits |= TIOCM_RTS;
-                       if (mode & (MSR_RI|MSR_TERI)) bits |= TIOCM_RI;
-                       *(int *)data = bits;
-               }
+               tiocm_xxx = TIOCM_LE;   /* XXX - always enabled while open */
+               mcr = com->mcr_image;
+               if (mcr & MCR_DTR)
+                       tiocm_xxx |= TIOCM_DTR;
+               if (mcr & MCR_RTS)
+                       tiocm_xxx |= TIOCM_RTS;
+               msr = com->prev_modem_status;
+               if (msr & MSR_CTS)
+                       tiocm_xxx |= TIOCM_CTS;
+               if (msr & MSR_DCD)
+                       tiocm_xxx |= TIOCM_CD;
+               if (msr & MSR_DSR)
+                       tiocm_xxx |= TIOCM_DSR;
+               /* XXX - MSR_TERI is too volatile. */
+               if (msr & (MSR_RI | MSR_TERI))
+                       tiocm_xxx |= TIOCM_RI;
+               *(int *)data = tiocm_xxx;
                break;
 #ifdef COM_BIDIR
        case TIOCMSBIDIR:
                break;
 #ifdef COM_BIDIR
        case TIOCMSBIDIR:
@@ -1066,6 +1098,20 @@ sioioctl(dev, cmd, data, flag, p)
                *(int *)data = com->bidir;
                break;
 #endif /* COM_BIDIR */
                *(int *)data = com->bidir;
                break;
 #endif /* COM_BIDIR */
+       case TIOCMSDTRWAIT:
+               /* must be root (XXX why?) */
+               if (p->p_ucred->cr_uid != 0)
+                       return(EPERM);
+
+               /* if it's the console, can't do it (XXX why?) */
+               if (UNIT(dev) == comconsole)
+                       return(ENOTTY);
+
+               com->dtr_wait = *(int *)data;
+               break;
+       case TIOCMGDTRWAIT:
+               *(int *)data = com->dtr_wait;
+               break;
        default:
                splx(s);
                return (ENOTTY);
        default:
                splx(s);
                return (ENOTTY);
@@ -1145,7 +1191,7 @@ repeat:
                         * there is room in the high-level buffer.
                         */
                        if (!(com->mcr_image & MCR_RTS)
                         * there is room in the high-level buffer.
                         */
                        if (!(com->mcr_image & MCR_RTS)
-                           && !(tp->t_state & TS_RTSBLOCK))
+                           && !(tp->t_state & TS_RTS_IFLOW))
                                outb(com->modem_ctl_port,
                                     com->mcr_image |= MCR_RTS);
                        enable_intr();
                                outb(com->modem_ctl_port,
                                     com->mcr_image |= MCR_RTS);
                        enable_intr();
@@ -1162,26 +1208,15 @@ repeat:
                        com_events -= LOTS_OF_EVENTS;
                        com->state &= ~CS_CHECKMSR;
                        enable_intr();
                        com_events -= LOTS_OF_EVENTS;
                        com->state &= ~CS_CHECKMSR;
                        enable_intr();
-                       if (delta_modem_status & MSR_DCD &&
-                           unit != comconsole) {
-#ifdef COM_BIDIR
+                       if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
                                if (com->prev_modem_status & MSR_DCD) {
                                        (*linesw[tp->t_line].l_modem)(tp, 1);
                                if (com->prev_modem_status & MSR_DCD) {
                                        (*linesw[tp->t_line].l_modem)(tp, 1);
-                                       com->softDCD = FALSE;
+#ifdef COM_BIDIR
                                        wakeup((caddr_t) &com->active_in);
                                        wakeup((caddr_t) &com->active_in);
-                               }
-#else
-                               if (com->prev_modem_status & MSR_DCD)
-                                        (*linesw[tp->t_line].l_modem)(tp, 1);
 #endif /* COM_BIDIR */
 #endif /* COM_BIDIR */
-                               else if ((*linesw[tp->t_line].l_modem)(tp, 0)
-                                        == 0) {
-                                       disable_intr();
-                                       outb(com->modem_ctl_port,
-                                            com->mcr_image
-                                            &= ~MCR_DTR);
-                                       enable_intr();
                                }
                                }
+                               else
+                                       (*linesw[tp->t_line].l_modem)(tp, 0);
                        }
                }
 
                        }
                }
 
@@ -1204,7 +1239,7 @@ repeat:
                                        total =
                                        com->error_counts[errnum] += delta;
                                        log(LOG_WARNING,
                                        total =
                                        com->error_counts[errnum] += delta;
                                        log(LOG_WARNING,
-                                       "com%d: %u more %s%s (total %lu)\n",
+                                       "sio%d: %u more %s%s (total %lu)\n",
                                            unit, delta, error_desc[errnum],
                                            delta == 1 ? "" : "s", total);
                                }
                                            unit, delta, error_desc[errnum],
                                            delta == 1 ? "" : "s", total);
                                }
@@ -1222,13 +1257,13 @@ repeat:
                        continue;
                if (com->state & CS_RTS_IFLOW
                    && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
                        continue;
                if (com->state & CS_RTS_IFLOW
                    && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
-                   && !(tp->t_state & TS_RTSBLOCK)
+                   && !(tp->t_state & TS_RTS_IFLOW)
                    /*
                     * XXX - need RTS flow control for all line disciplines.
                     * Only have it in standard one now.
                     */
                    && linesw[tp->t_line].l_rint == ttyinput) {
                    /*
                     * XXX - need RTS flow control for all line disciplines.
                     * Only have it in standard one now.
                     */
                    && linesw[tp->t_line].l_rint == ttyinput) {
-                       tp->t_state |= TS_RTSBLOCK;
+                       tp->t_state |= TS_RTS_IFLOW;
                        ttstart(tp);
                }
                /*
                        ttstart(tp);
                }
                /*
@@ -1350,12 +1385,13 @@ comparam(tp, t)
         * error bits, but that is acceptable here.
         */
        disable_intr();
         * error bits, but that is acceptable here.
         */
        disable_intr();
+retry:
        com->state &= ~CS_TTGO;
        enable_intr();
        while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
               != (LSR_TSRE | LSR_TXRDY)) {
                error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
        com->state &= ~CS_TTGO;
        enable_intr();
        while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
               != (LSR_TSRE | LSR_TXRDY)) {
                error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
-                                "comparam", 1);
+                                "sioparam", 1);
                if (error != 0 && error != EAGAIN) {
                        if (!(tp->t_state & TS_TTSTOP)) {
                                disable_intr();
                if (error != 0 && error != EAGAIN) {
                        if (!(tp->t_state & TS_TTSTOP)) {
                                disable_intr();
@@ -1368,6 +1404,17 @@ comparam(tp, t)
        }
 
        disable_intr();         /* very important while com_data is hidden */
        }
 
        disable_intr();         /* very important while com_data is hidden */
+
+       /*
+        * XXX - clearing CS_TTGO is not sufficient to stop further output,
+        * because compoll() calls comstart() which set it again because
+        * TS_TTSTOP is set.  Clearing TS_TTSTOP would not be sufficient,
+        * for similar reasons.
+        */
+       if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+              != (LSR_TSRE | LSR_TXRDY))
+               goto retry;
+
        outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
        outb(iobase + com_dlbl, divisor & 0xFF);
        outb(iobase + com_dlbh, (u_int) divisor >> 8);
        outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
        outb(iobase + com_dlbl, divisor & 0xFF);
        outb(iobase + com_dlbh, (u_int) divisor >> 8);
@@ -1383,19 +1430,17 @@ comparam(tp, t)
         * Set up state to handle output flow control.
         * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
         * Now has 16+ msec latency, while CTS flow has 50- usec latency.
         * Set up state to handle output flow control.
         * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
         * Now has 16+ msec latency, while CTS flow has 50- usec latency.
-        * Note that DCD flow control stupidly uses the same state flag
-        * (TS_TTSTOP) as XON/XOFF flow control.
         */
        com->state &= ~CS_CTS_OFLOW;
        com->state |= CS_ODEVREADY;
        if (cflag & CCTS_OFLOW) {
                com->state |= CS_CTS_OFLOW;
         */
        com->state &= ~CS_CTS_OFLOW;
        com->state |= CS_ODEVREADY;
        if (cflag & CCTS_OFLOW) {
                com->state |= CS_CTS_OFLOW;
-               if (!(com->prev_modem_status & MSR_CTS))
+               if (!(com->last_modem_status & MSR_CTS))
                        com->state &= ~CS_ODEVREADY;
        }
 
                        com->state &= ~CS_ODEVREADY;
        }
 
-       enable_intr();
        siointr(unit);          /* recover from fiddling with CS_TTGO */
        siointr(unit);          /* recover from fiddling with CS_TTGO */
+       enable_intr();
        splx(s);
        return (0);
 }
        splx(s);
        return (0);
 }
@@ -1416,15 +1461,13 @@ comstart(tp)
                com->state &= ~CS_TTGO;
        else
                com->state |= CS_TTGO;
                com->state &= ~CS_TTGO;
        else
                com->state |= CS_TTGO;
-       if (tp->t_state & TS_RTSBLOCK) {
+       if (tp->t_state & TS_RTS_IFLOW) {
                if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
                        outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
        }
        else {
                if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
                        outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
        }
        else {
-               if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater) {
-                       tp->t_state &= ~TS_RTSBLOCK;
+               if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
                        outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
                        outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
-               }
        }
        enable_intr();
        if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
        }
        enable_intr();
        if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
@@ -1488,48 +1531,37 @@ commctl(com, bits, how)
        int             bits;
        int             how;
 {
        int             bits;
        int             how;
 {
+#ifdef COM_MULTIPORT
+       if (how != DMBIC && !com->multiport)
+#else
+       if (how != DMBIC)
+#endif
+               bits |= MCR_IENABLE;
        disable_intr();
        switch (how) {
        case DMSET:
        disable_intr();
        switch (how) {
        case DMSET:
-#ifdef COM_MULTIPORT
-               /* YYY maybe your card doesn't want IENABLE to be reset? */
-               if(com->multiport)
-                       outb(com->modem_ctl_port,
-                            com->mcr_image = bits);
-               else
-#endif /* COM_MULTIPORT */
-                       outb(com->modem_ctl_port,
-                            com->mcr_image = bits | MCR_IENABLE);
+               outb(com->modem_ctl_port, com->mcr_image = bits);
                break;
        case DMBIS:
                outb(com->modem_ctl_port, com->mcr_image |= bits);
                break;
        case DMBIC:
                break;
        case DMBIS:
                outb(com->modem_ctl_port, com->mcr_image |= bits);
                break;
        case DMBIC:
-#ifdef COM_MULTIPORT
-               /* YYY maybe your card doesn't want IENABLE to be reset? */
-               if(com->multiport)
-                       outb(com->modem_ctl_port,
-                            com->mcr_image &= ~(bits));
-               else
-#endif /* COM_MULTIPORT */
-                       outb(com->modem_ctl_port,
-                            com->mcr_image &= ~(bits & ~MCR_IENABLE));
-               break;
-       case DMGET:
-               bits = com->prev_modem_status | (com->mcr_image << 8);
+               outb(com->modem_ctl_port, com->mcr_image &= ~bits);
                break;
        }
        enable_intr();
        return (bits);
 }
 
                break;
        }
        enable_intr();
        return (bits);
 }
 
-static void
-comwakeup()
+static nonint
+comwakeup(chan, ticks)
+       caddr_t chan;
+       int ticks;
 {
        struct com_s    *com;
        int             unit;
 
 {
        struct com_s    *com;
        int             unit;
 
-       timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1);
+       timeout(comwakeup, (caddr_t) NULL, 1);
        if (com_events != 0)
                /* schedule compoll() to run when the cpl allows */
                schedsoftcom();
        if (com_events != 0)
                /* schedule compoll() to run when the cpl allows */
                schedsoftcom();
@@ -1543,34 +1575,14 @@ comwakeup()
                        enable_intr();
                }
        }
                        enable_intr();
                }
        }
+       return (0);
 }
 
 void
 }
 
 void
-softsio0() { compoll(); }
-
-void
-softsio1() { compoll(); }
-
-void
-softsio2() { compoll(); }
-
-void
-softsio3() { compoll(); }
-
-void
-softsio4() { compoll(); }
-
-void
-softsio5() { compoll(); }
-
-void
-softsio6() { compoll(); }
-
-void
-softsio7() { compoll(); }
-
-void
-softsio8() { compoll(); }
+softsio1()
+{
+       compoll();
+}
 
 /*
  * Following are all routines needed for COM to act as console
 
 /*
  * Following are all routines needed for COM to act as console
@@ -1699,6 +1711,10 @@ siocnputc(dev, c)
 /*
  * 10 Feb 93   Jordan K. Hubbard       Added select code
  * 27 May 93   Rodney W. Grimes        Stole the select code from com.c.pl5
 /*
  * 10 Feb 93   Jordan K. Hubbard       Added select code
  * 27 May 93   Rodney W. Grimes        Stole the select code from com.c.pl5
+ *
+ * XXX - the standard com.c never needed this, but we need it because
+ * ttselect() can't determine the tty struct because stuff is encoded in the
+ * high bit of the minor number.
  */
 
 int
  */
 
 int
@@ -1707,7 +1723,7 @@ sioselect(dev, rw, p)
        int rw;
        struct proc *p;
 {
        int rw;
        struct proc *p;
 {
-       register struct tty *tp = &sio_tty[UNIT(dev)];
+       struct tty *tp = &sio_tty[UNIT(dev)];
        int nread;
        int s = spltty();
         struct proc *selp;
        int nread;
        int s = spltty();
         struct proc *selp;
@@ -1716,7 +1732,7 @@ sioselect(dev, rw, p)
 
        case FREAD:
                nread = ttnread(tp);
 
        case FREAD:
                nread = ttnread(tp);
-               if (nread > 0 || 
+               if (nread > 0 ||
                   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
                        goto win;
                if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
                   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
                        goto win;
                if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
index 1bea7b2..002180b 100644 (file)
@@ -32,7 +32,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.c 7.44 (Berkeley) 5/28/91
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.c 7.44 (Berkeley) 5/28/91
- *     $Id: tty.c,v 1.6 1993/11/07 21:44:44 wollman Exp $
+ *     $Id: tty.c,v 1.7 1993/11/08 19:15:00 ache Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 
 #include "vm/vm.h"
 
 
 #include "vm/vm.h"
 
+/*
+ * Input control starts when we would not be able to fit the maximum
+ * contents of the ping-pong buffers and finishes when we would be able
+ * to fit that much plus 1/8 more.
+ */
+#define        I_HIGH_WATER    (TTYHOG - 2 * 256)      /* XXX */
+#define        I_LOW_WATER     ((TTYHOG - 2 * 256) * 7 / 8)    /* XXX */
+
+/* XXX RB_LEN() is too slow. */
+#define INPUT_LEN(tp)  (RB_LEN(&(tp)->t_can) + RB_LEN(&(tp)->t_raw))
+#undef MAX_INPUT               /* XXX wrong in <sys/syslimits.h> */
+#define        MAX_INPUT       TTYHOG
+
 static int proc_compare __P((struct proc *p1, struct proc *p2));
 
 /* symbolic sleep message strings */
 static int proc_compare __P((struct proc *p1, struct proc *p2));
 
 /* symbolic sleep message strings */
@@ -221,36 +234,72 @@ ttyflush(tp, rw)
                        tp->t_state &= ~TS_WCOLL;
                }
        }
                        tp->t_state &= ~TS_WCOLL;
                }
        }
+       if (rw & FREAD) {
+               if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW)
+                   && INPUT_LEN(tp) < I_LOW_WATER) {
+                       int out_cc;
+                       int t_state;
+
+                       /*
+                        * We delayed turning off input flow control in case
+                        * we have to send a start character and the output
+                        * queue was previously full.  Sending a start char
+                        * is still tricky because we don't want to add a
+                        * new obstruction to draining the output queue.
+                        */
+                       out_cc = RB_LEN(&tp->t_out);
+                       t_state = tp->t_state;
+                       ttyunblock(tp);
+                       tp->t_state &= ~TS_TBLOCK;
+                       if (t_state & TS_TBLOCK && RB_LEN(&tp->t_out) != 0)
+                               ttysleep(tp, (caddr_t)&tp->t_out, TTIPRI,
+                                        ttyout, hz / 10);
+                       if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) {
+                               (*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE);
+                               flushq(&tp->t_out);
+                       }
+               }
+       }
        splx(s);
 }
 
 /*
        splx(s);
 }
 
 /*
- * Send stop character on input overflow.
+ * Handle input high water.  Send stop character for the IXOFF case.  Turn
+ * on all enabled input flow control bits and propagate the change to the
+ * driver.
  */
  */
+/* static void */
 ttyblock(tp)
 ttyblock(tp)
-       register struct tty *tp;
+       struct tty *tp;
 {
 {
-       register x;
-       int rawcc, cancc;
 
 
-       rawcc = RB_LEN(&tp->t_raw);
-       cancc = RB_LEN(&tp->t_can);
-       x = rawcc + cancc;
-       if (rawcc > TTYHOG) {
-               ttyflush(tp, FREAD|FWRITE);
-       }
-       /*
-        * Block further input iff:
-        * Current input > threshold AND input is available to user program
-        */
-       if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
-           ((tp->t_lflag&ICANON) == 0) || (cancc > 0)) {
-               if (tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
-                   putc(tp->t_cc[VSTOP], &tp->t_out);
-               }
-               tp->t_state |= TS_TBLOCK;       /* XXX - should be TS_RTSBLOCK? */
-               ttstart(tp);
-       }
+       if ((tp->t_state & TS_TBLOCK) == 0
+           && tp->t_cc[VSTOP] != _POSIX_VDISABLE
+           && putc(tp->t_cc[VSTOP], &tp->t_out) == 0)
+               tp->t_state |= TS_TBLOCK;
+       if (tp->t_cflag & CDTR_IFLOW)
+               tp->t_state |= TS_DTR_IFLOW;
+       if (tp->t_cflag & CRTS_IFLOW)
+               tp->t_state |= TS_RTS_IFLOW;
+       ttstart(tp);
+}
+
+/*
+ * Handle input low water.  Send start character for the IXOFF case.  Turn
+ * off our input flow control bits and propagate the change to the driver.
+ */
+/* static */
+int
+ttyunblock(tp)
+       struct tty *tp;
+{
+
+       if (tp->t_state & TS_TBLOCK
+           && tp->t_cc[VSTART] != _POSIX_VDISABLE
+           && putc(tp->t_cc[VSTART], &tp->t_out) == 0)
+               tp->t_state &= ~TS_TBLOCK;
+       tp->t_state &= ~TS_HW_IFLOW;
+       ttstart(tp);
 }
 
 ttstart(tp)
 }
 
 ttstart(tp)
@@ -687,10 +736,6 @@ ttyclose(tp)
        ttyflush(tp, FREAD|FWRITE);
        tp->t_session = NULL;
        tp->t_pgrp = NULL;
        ttyflush(tp, FREAD|FWRITE);
        tp->t_session = NULL;
        tp->t_pgrp = NULL;
-/*
- * XXX - do we need to send cc[VSTART] or do a ttstart() here in some cases?
- * (TS_TBLOCK and TS_RTSBLOCK are being cleared.)
- */
        tp->t_state = 0;
        tp->t_gen++;
        return (0);
        tp->t_state = 0;
        tp->t_gen++;
        return (0);
@@ -710,10 +755,10 @@ ttymodem(tp, flag)
                 * MDMBUF: do flow control according to carrier flag
                 */
                if (flag) {
                 * MDMBUF: do flow control according to carrier flag
                 */
                if (flag) {
-                       tp->t_state &= ~TS_TTSTOP;
+                       tp->t_state &= ~TS_CAR_OFLOW;
                        ttstart(tp);
                        ttstart(tp);
-               } else if ((tp->t_state&TS_TTSTOP) == 0) {
-                       tp->t_state |= TS_TTSTOP;
+               } else if ((tp->t_state&TS_CAR_OFLOW) == 0) {
+                       tp->t_state |= TS_CAR_OFLOW;
                        (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
                }
        } else if (flag == 0) {
                        (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
                }
        } else if (flag == 0) {
@@ -809,6 +854,17 @@ ttyinput(c, tp)
                tk_rawcc++;
                tp->t_rawcc++;
        }
                tk_rawcc++;
                tp->t_rawcc++;
        }
+       /*
+        * If input flow control is enabled and not yet invoked, check the
+        * high water mark.  Block further input iff:
+        * current input > threshold AND input is available to user program.
+        * The 3 is slop for PARMRK.
+        */
+       if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0
+            || tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0)
+           && INPUT_LEN(tp) > I_HIGH_WATER - 3
+           && ((lflag & ICANON) == 0 || RB_LEN(&tp->t_can) != 0))
+               ttyblock(tp);
        /*
         * Handle exceptional conditions (break, parity, framing).
         */
        /*
         * Handle exceptional conditions (break, parity, framing).
         */
@@ -827,6 +883,8 @@ ttyinput(c, tp)
                                goto endcase;
                        else if (iflag&PARMRK) {
 parmrk:
                                goto endcase;
                        else if (iflag&PARMRK) {
 parmrk:
+                               if (INPUT_LEN(tp) > MAX_INPUT - 3)
+                                       goto input_overflow;
                                putc(0377|TTY_QUOTE, &tp->t_raw);
                                putc(0|TTY_QUOTE, &tp->t_raw);
                                putc(c|TTY_QUOTE, &tp->t_raw);
                                putc(0377|TTY_QUOTE, &tp->t_raw);
                                putc(0|TTY_QUOTE, &tp->t_raw);
                                putc(c|TTY_QUOTE, &tp->t_raw);
@@ -835,11 +893,6 @@ parmrk:
                                c = 0;
                }
        }
                                c = 0;
                }
        }
-       /*
-        * In tandem mode, check high water mark.
-        */
-       if (iflag&IXOFF)
-               ttyblock(tp);
        if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
                c &= ~0x80;
        if ((tp->t_lflag&EXTPROC) == 0) {
        if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
                c &= ~0x80;
        if ((tp->t_lflag&EXTPROC) == 0) {
@@ -879,7 +932,7 @@ parmrk:
                                else {
                                        ttyflush(tp, FWRITE);
                                        ttyecho(c, tp);
                                else {
                                        ttyflush(tp, FWRITE);
                                        ttyecho(c, tp);
-                                       if (RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can))
+                                       if (INPUT_LEN(tp) != 0)
                                                ttyretype(tp);
                                        tp->t_lflag |= FLUSHO;
                                }
                                                ttyretype(tp);
                                        tp->t_lflag |= FLUSHO;
                                }
@@ -992,6 +1045,13 @@ parmrk:
                        c = unputc(&tp->t_raw);
                        if (c == -1)
                                goto endcase;
                        c = unputc(&tp->t_raw);
                        if (c == -1)
                                goto endcase;
+                       /*
+                        * Handle one-letter word cases.
+                        */
+                       if (c == ' ' || c == '\t') {
+                               putc(c, &tp->t_raw);
+                               goto endcase;
+                       }
                        ctype = ISALPHA(c);
                        /*
                         * erase rest of word
                        ctype = ISALPHA(c);
                        /*
                         * erase rest of word
@@ -1026,12 +1086,13 @@ parmrk:
        /*
         * Check for input buffer overflow
         */
        /*
         * Check for input buffer overflow
         */
-       if (RB_LEN(&tp->t_raw)+RB_LEN(&tp->t_can) >= TTYHOG) {
+       if (INPUT_LEN(tp) >= MAX_INPUT) {
+input_overflow:
                if (iflag&IMAXBEL) {
                        if (RB_LEN(&tp->t_out) < tp->t_hiwat)
                                (void) ttyoutput(CTRL('g'), tp);
                } else
                if (iflag&IMAXBEL) {
                        if (RB_LEN(&tp->t_out) < tp->t_hiwat)
                                (void) ttyoutput(CTRL('g'), tp);
                } else
-                       ttyflush(tp, FREAD | FWRITE);
+                       ttyflush(tp, FREAD);
                goto endcase;
        }
        /*
                goto endcase;
        }
        /*
@@ -1299,25 +1360,13 @@ loop:
                first = 0;
        }
        /*
                first = 0;
        }
        /*
-        * Look to unblock output now that (presumably)
+        * Look to unblock input now that (presumably)
         * the input queue has gone down.
         */
         * the input queue has gone down.
         */
-#if 0
-       if (tp->t_state&TS_TBLOCK && RB_LEN(&tp->t_raw) < TTYHOG/5) {
-               if (cc[VSTART] != _POSIX_VDISABLE &&
-                   putc(cc[VSTART], &tp->t_out) == 0) {
-                       tp->t_state &= ~TS_TBLOCK;
-                       ttstart(tp);
-               }
-       }
-#else
-#define        TS_RTSBLOCK     TS_TBLOCK       /* XXX */
-#define        RB_I_LOW_WATER  ((RBSZ - 2 * 256) * 7 / 8)      /* XXX */
-       if (tp->t_state&TS_RTSBLOCK && RB_LEN(&tp->t_raw) <= RB_I_LOW_WATER) {
-               tp->t_state &= ~TS_RTSBLOCK;
-               ttstart(tp);
-       }
-#endif
+       if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW)
+           && INPUT_LEN(tp) <= I_LOW_WATER)
+               ttyunblock(tp);
+
        return (error);
 }
 
        return (error);
 }
 
@@ -1460,7 +1509,6 @@ loop:
                                        if (ttyoutput(*cp, tp) >= 0) {
                                            /* no c-lists, wait a bit */
                                            ttstart(tp);
                                        if (ttyoutput(*cp, tp) >= 0) {
                                            /* no c-lists, wait a bit */
                                            ttstart(tp);
-printf("\nttysleep - no c-lists\n");   /* XXX */
                                            if (error = ttysleep(tp, 
                                                (caddr_t)&lbolt,
                                                 TTOPRI | PCATCH, ttybuf, 0))
                                            if (error = ttysleep(tp, 
                                                (caddr_t)&lbolt,
                                                 TTOPRI | PCATCH, ttybuf, 0))
index 0436e76..eb49978 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ioctl.h       7.19 (Berkeley) 6/26/91
  * SUCH DAMAGE.
  *
  *     from: @(#)ioctl.h       7.19 (Berkeley) 6/26/91
- *     $Id$
+ *     $Id: ioctl.h,v 1.4 1993/10/12 04:57:33 rgrimes Exp $
  */
 
 #ifndef        _IOCTL_H_
  */
 
 #ifndef        _IOCTL_H_
@@ -149,6 +149,8 @@ struct ttysize {
 #define        TIOCDRAIN       _IO('t', 94)            /* wait till output drained */
 #define        TIOCMSBIDIR     _IOW('t', 93, int)      /* modem: set bidir cap. */
 #define        TIOCMGBIDIR     _IOR('t', 92, int)      /* modem: get bidir cap. */
 #define        TIOCDRAIN       _IO('t', 94)            /* wait till output drained */
 #define        TIOCMSBIDIR     _IOW('t', 93, int)      /* modem: set bidir cap. */
 #define        TIOCMGBIDIR     _IOR('t', 92, int)      /* modem: get bidir cap. */
+#define TIOCMSDTRWAIT  _IOW('t', 91, int)      /* modem: set wait on close */
+#define TIOCMGDTRWAIT  _IOR('t', 90, int)      /* modem: get wait on close */
 
 #define        TTYDISC         0               /* termios tty line discipline */
 #define        NETLDISC        1               /* line discip for berk net */
 
 #define        TTYDISC         0               /* termios tty line discipline */
 #define        NETLDISC        1               /* line discip for berk net */
index d120cc8..15a461e 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.h 7.10 (Berkeley) 6/26/91
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.h 7.10 (Berkeley) 6/26/91
- *     $Id$
+ *     $Id: tty.h,v 1.4 1993/10/16 17:18:06 rgrimes Exp $
  */
 
 #ifndef _SYS_TTY_H_
  */
 
 #ifndef _SYS_TTY_H_
@@ -154,7 +154,12 @@ extern     struct ttychars ttydefaults;
 #define        TS_LNCH         0x080000        /* next character is literal */
 #define        TS_TYPEN        0x100000        /* retyping suspended input (PENDIN) */
 #define        TS_CNTTB        0x200000        /* counting tab width, ignore FLUSHO */
 #define        TS_LNCH         0x080000        /* next character is literal */
 #define        TS_TYPEN        0x100000        /* retyping suspended input (PENDIN) */
 #define        TS_CNTTB        0x200000        /* counting tab width, ignore FLUSHO */
+/* flow-control-invoked bits */
+#define        TS_CAR_OFLOW    0x0400000       /* for MDMBUF (XXX handle in driver) */
+#define        TS_DTR_IFLOW    0x2000000       /* not implemented */
+#define        TS_RTS_IFLOW    0x4000000       /* for CRTS_IFLOW */
 
 
+#define        TS_HW_IFLOW     (TS_DTR_IFLOW | TS_RTS_IFLOW)
 #define        TS_LOCAL        (TS_BKSL|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
 
 /* define partab character types */
 #define        TS_LOCAL        (TS_BKSL|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
 
 /* define partab character types */