This patch adds support for multiple simultaneous low level consoles
to the kernel.  In essence, it is equivalent to the -D flag in the
/boot.config file.

Support can be turned on by executing 'boot -D' from the loader, or 
by using the comcontrol program (which is appended to the end of the
patch).

The motivation for performing this work (other than wanting to be able
to use ddb on vidconsol and comconsole interchangeably) is the upcoming
network console support, which requires the ability to add a console 
after the system is up.

Objections and bugs aside, I plan to commit this shortly.
-- 
Jonathan

Index: kern/tty_cons.c
===================================================================
RCS file: /ncvs/src/sys/kern/tty_cons.c,v
retrieving revision 1.92
diff -u -r1.92 tty_cons.c
--- kern/tty_cons.c     2001/09/12 08:37:46     1.92
+++ kern/tty_cons.c     2001/10/20 03:23:04
@@ -44,11 +44,15 @@
 #include <sys/conf.h>
 #include <sys/cons.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/namei.h>
 #include <sys/proc.h>
+#include <sys/queue.h>
 #include <sys/reboot.h>
 #include <sys/sysctl.h>
 #include <sys/tty.h>
 #include <sys/uio.h>
+#include <sys/vnode.h>
 
 #include <machine/cpu.h>
 
@@ -78,47 +82,43 @@
        /* kqfilter */  cnkqfilter,
 };
 
-static dev_t   cn_dev_t;       /* seems to be never really used */
+struct cn_device {
+       STAILQ_ENTRY(cn_device) cnd_next;
+       char            cnd_name[16];
+       struct          vnode *cnd_vp;
+       struct          consdev *cnd_cn;
+};
+
+#define CNDEVPATHMAX   32
+#define CNDEVTAB_SIZE  4
+static struct cn_device cn_devtab[CNDEVTAB_SIZE];
+static STAILQ_HEAD(, cn_device) cn_devlist =
+    STAILQ_HEAD_INITIALIZER(cn_devlist);
+
+#define CND_INVALID(cnd, td)                                           \
+       (cnd == NULL || cnd->cnd_vp == NULL ||                          \
+           (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
+
 static udev_t  cn_udev_t;
 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
        &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
 
-static int cn_mute;
-
 int    cons_unavail = 0;       /* XXX:
                                 * physical console not available for
                                 * input (i.e., it is in graphics mode)
                                 */
-
-static u_char cn_is_open;              /* nonzero if logical console is open */
-static int openmode, openflag;         /* how /dev/console was openned */
+static int cn_mute;
+static int openflag;                   /* how /dev/console was opened */
+static int cn_is_open;
 static dev_t cn_devfsdev;              /* represents the device private info */
-static u_char cn_phys_is_open;         /* nonzero if physical device is open */
-static d_close_t *cn_phys_close;       /* physical device close function */
-static d_open_t *cn_phys_open;         /* physical device open function */
-       struct consdev *cn_tab;         /* physical console device info */
 
 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 SET_DECLARE(cons_set, struct consdev);
 
 void
-cninit()
+cninit(void)
 {
-       struct consdev *best_cp, *cp, **list;
-
-       /*
-        * Find the first console with the highest priority.
-        */
-       best_cp = NULL;
-       SET_FOREACH(list, cons_set) {
-               cp = *list;
-               if (cp->cn_probe == NULL)
-                       continue;
-               (*cp->cn_probe)(cp);
-               if (cp->cn_pri > CN_DEAD &&
-                   (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
-                       best_cp = cp;
-       }
+       struct consdev *best_cn, *cn, **list;
 
        /*
         * Check if we should mute the console (for security reasons perhaps)
@@ -131,74 +131,176 @@
                        |RB_VERBOSE
                        |RB_ASKNAME
                        |RB_CONFIG)) == RB_MUTE);
-       
+
        /*
-        * If no console, give up.
+        * Find the first console with the highest priority.
         */
-       if (best_cp == NULL) {
-               if (cn_tab != NULL && cn_tab->cn_term != NULL)
-                       (*cn_tab->cn_term)(cn_tab);
-               cn_tab = best_cp;
+       best_cn = NULL;
+       SET_FOREACH(list, cons_set) {
+               cn = *list;
+               if (cn->cn_probe == NULL)
+                       continue;
+               cn->cn_probe(cn);
+               if (cn->cn_pri == CN_DEAD)
+                       continue;
+               if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
+                       best_cn = cn;
+               if (boothowto & RB_MULTIPLE) {
+                       /*
+                        * Initialize console, and attach to it.
+                        */
+                       cnadd(cn);
+                       cn->cn_init(cn);
+               }
+       }
+       if (best_cn == NULL)
                return;
+       if ((boothowto & RB_MULTIPLE) == 0) {
+               cnadd(best_cn);
+               best_cn->cn_init(best_cn);
        }
-
        /*
-        * Initialize console, then attach to it.  This ordering allows
-        * debugging using the previous console, if any.
+        * Make the best console the preferred console.
         */
-       (*best_cp->cn_init)(best_cp);
-       if (cn_tab != NULL && cn_tab != best_cp) {
-               /* Turn off the previous console.  */
-               if (cn_tab->cn_term != NULL)
-                       (*cn_tab->cn_term)(cn_tab);
-       }
-       cn_tab = best_cp;
+       cnselect(best_cn);
+}
+
+/* add a new physical console to back the virtual console */
+int
+cnadd(struct consdev *cn)
+{
+       struct cn_device *cnd;
+       int i;
+
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
+               if (cnd->cnd_cn == cn)
+                       return (0);
+       for (i = 0; i < CNDEVTAB_SIZE; i++) {
+               cnd = &cn_devtab[i];
+               if (cnd->cnd_cn == NULL)
+                       break;
+       }
+       if (cnd->cnd_cn != NULL)
+               return (ENOMEM);
+       cnd->cnd_cn = cn;
+       STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
+       return (0);
 }
 
 void
-cninit_finish()
+cnremove(struct consdev *cn)
 {
-       struct cdevsw *cdp;
+       struct cn_device *cnd;
 
-       if ((cn_tab == NULL) || cn_mute)
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+               if (cnd->cnd_cn != cn)
+                       continue;
+               STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
+               if (cnd->cnd_vp != NULL)
+                       vn_close(cnd->cnd_vp, openflag, NOCRED, NULL);
+               cnd->cnd_vp = NULL;
+               cnd->cnd_cn = NULL;
+               cnd->cnd_name[0] = '\0';
+#if 0
+               /*
+                * XXX
+                * syscons gets really confused if console resources are
+                * freed after the system has initialized.
+                */
+               if (cn->cn_term != NULL)
+                       cn->cn_term(cn);
+#endif
                return;
-
-       /*
-        * Hook the open and close functions.
-        */
-       cdp = devsw(cn_tab->cn_dev);
-       if (cdp != NULL) {
-               cn_phys_close = cdp->d_close;
-               cdp->d_close = cnclose;
-               cn_phys_open = cdp->d_open;
-               cdp->d_open = cnopen;
        }
-       cn_dev_t = cn_tab->cn_dev;
-       cn_udev_t = dev2udev(cn_dev_t);
 }
 
-static void
-cnuninit(void)
+void
+cnselect(struct consdev *cn)
 {
-       struct cdevsw *cdp;
+       struct cn_device *cnd;
 
-       if (cn_tab == NULL)
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+               if (cnd->cnd_cn != cn)
+                       continue;
+               if (cnd == STAILQ_FIRST(&cn_devlist))
+                       return;
+               STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
+               STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
                return;
+       }
+}
 
-       /*
-        * Unhook the open and close functions.
-        */
-       cdp = devsw(cn_tab->cn_dev);
-       if (cdp != NULL) {
-               cdp->d_close = cn_phys_close;
-               cdp->d_open = cn_phys_open;
-       }
-       cn_phys_close = NULL;
-       cn_phys_open = NULL;
-       cn_dev_t = NODEV;
-       cn_udev_t = NOUDEV;
+void
+cndebug(char *str)
+{
+       int i, len;
+
+       len = strlen(str);
+       cnputc('>'); cnputc('>'); cnputc('>'); cnputc(' '); 
+       for (i = 0; i < len; i++)
+               cnputc(str[i]);
+       cnputc('\n');
+}
+
+static int
+sysctl_kern_console(SYSCTL_HANDLER_ARGS)
+{
+       struct cn_device *cnd;
+       struct consdev *cp, **list;
+       char *name, *p;
+       int delete, len, error;
+
+       len = 2;
+       SET_FOREACH(list, cons_set) {
+               cp = *list;
+               if (cp->cn_dev != NULL)
+                       len += strlen(devtoname(cp->cn_dev)) + 1;
+       }
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
+               len += strlen(devtoname(cnd->cnd_cn->cn_dev)) + 1;
+       len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX;
+       MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO);
+       p = name;
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
+               p += sprintf(p, "%s,", devtoname(cnd->cnd_cn->cn_dev));
+       *p++ = '/';
+       SET_FOREACH(list, cons_set) {
+               cp = *list;
+               if (cp->cn_dev != NULL)
+                       p += sprintf(p, "%s,", devtoname(cp->cn_dev));
+       }
+       error = sysctl_handle_string(oidp, name, len, req);
+       if (error == 0 && req->newptr != NULL) {
+               p = name;
+               error = ENXIO;
+               delete = 0;
+               if (*p == '-') {
+                       delete = 1;
+                       p++;
+               }
+               SET_FOREACH(list, cons_set) {
+                       cp = *list;
+                       if (cp->cn_dev == NULL ||
+                           strcmp(p, devtoname(cp->cn_dev)) != 0)
+                               continue;
+                       if (delete) {
+                               cnremove(cp);
+                               error = 0;
+                       } else {
+                               error = cnadd(cp);
+                               if (error == 0)
+                                       cnselect(cp);
+                       }
+                       break;
+               }
+       }
+       FREE(name, M_TEMP);
+       return (error);
 }
 
+SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW,
+       0, 0, sysctl_kern_console, "A", "Console device control");
+
 /*
  * User has changed the state of the console muting.
  * This may require us to open or close the device in question.
@@ -211,165 +313,123 @@
 
        ocn_mute = cn_mute;
        error = sysctl_handle_int(oidp, &cn_mute, 0, req);
-       if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
-               if(ocn_mute && !cn_mute) {
-                       /*
-                        * going from muted to unmuted.. open the physical dev 
-                        * if the console has been openned
-                        */
-                       cninit_finish();
-                       if(cn_is_open)
-                               /* XXX curthread is not what we want really */
-                               error = cnopen(cn_dev_t, openflag,
-                                       openmode, curthread);
-                       /* if it failed, back it out */
-                       if ( error != 0) cnuninit();
-               } else if (!ocn_mute && cn_mute) {
-                       /*
-                        * going from unmuted to muted.. close the physical dev 
-                        * if it's only open via /dev/console
-                        */
-                       if(cn_is_open)
-                               error = cnclose(cn_dev_t, openflag,
-                                       openmode, curthread);
-                       if ( error == 0) cnuninit();
-               }
-               if (error != 0) {
-                       /* 
-                        * back out the change if there was an error
-                        */
-                       cn_mute = ocn_mute;
-               }
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+       if (ocn_mute && !cn_mute && cn_is_open)
+               error = cnopen(NODEV, openflag, 0, curthread);
+       else if (!ocn_mute && cn_mute && cn_is_open) {
+               error = cnclose(NODEV, openflag, 0, curthread);
+               cn_is_open = 1;         /* XXX hack */
        }
        return (error);
 }
 
 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
-       0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
+       0, sizeof(cn_mute), sysctl_kern_consmute, "I", "");
 
 static int
-cnopen(dev, flag, mode, td)
-       dev_t dev;
-       int flag, mode;
-       struct thread *td;
+cn_devopen(struct cn_device *cnd, struct thread *td, int forceopen)
 {
-       dev_t cndev, physdev;
-       int retval = 0;
+       char path[CNDEVPATHMAX];
+        struct nameidata nd;
+       dev_t dev;
+       int error;
 
-       if (cn_tab == NULL || cn_phys_open == NULL)
-               return (0);
-       cndev = cn_tab->cn_dev;
-       physdev = (major(dev) == major(cndev) ? dev : cndev);
-       /*
-        * If mute is active, then non console opens don't get here
-        * so we don't need to check for that. They 
-        * bypass this and go straight to the device.
-        */
-       if(!cn_mute)
-               retval = (*cn_phys_open)(physdev, flag, mode, td);
-       if (retval == 0) {
-               /* 
-                * check if we openned it via /dev/console or 
-                * via the physical entry (e.g. /dev/sio0).
-                */
-               if (dev == cndev)
-                       cn_phys_is_open = 1;
-               else if (physdev == cndev) {
-                       openmode = mode;
-                       openflag = flag;
-                       cn_is_open = 1;
+       if (cnd->cnd_vp != NULL) {
+               if (!forceopen) {
+                       dev = cnd->cnd_vp->v_rdev;
+                       return ((*devsw(dev)->d_open)(dev, openflag, 0, td));
                }
-               dev->si_tty = physdev->si_tty;
+               vn_close(cnd->cnd_vp, openflag, td->td_proc->p_ucred, td);
+               cnd->cnd_vp = NULL;
+       }
+       if (cnd->cnd_name[0] == '\0')
+               strncpy(cnd->cnd_name, devtoname(cnd->cnd_cn->cn_dev),
+                   sizeof(cnd->cnd_name));
+       snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_name);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
+       error = vn_open(&nd, &openflag, 0);
+       if (error == 0) {
+               NDFREE(&nd, NDF_ONLY_PNBUF);
+               VOP_UNLOCK(nd.ni_vp, 0, td);
+               if (nd.ni_vp->v_type == VCHR)
+                       cnd->cnd_vp = nd.ni_vp;
+               else
+                       vn_close(nd.ni_vp, openflag, td->td_proc->p_ucred, td);
        }
-       return (retval);
+       return (cnd->cnd_vp != NULL);
 }
 
 static int
-cnclose(dev, flag, mode, td)
-       dev_t dev;
-       int flag, mode;
-       struct thread *td;
+cnopen(dev_t dev, int flag, int mode, struct thread *td)
 {
-       dev_t cndev;
-       struct tty *cn_tp;
+       struct cn_device *cnd;
 
-       if (cn_tab == NULL || cn_phys_open == NULL)
+       openflag = flag;
+       cn_is_open = 1;                 /* console is logically open */
+       if (cn_mute)
                return (0);
-       cndev = cn_tab->cn_dev;
-       cn_tp = cndev->si_tty;
-       /*
-        * act appropriatly depending on whether it's /dev/console
-        * or the pysical device (e.g. /dev/sio) that's being closed.
-        * in either case, don't actually close the device unless
-        * both are closed.
-        */
-       if (dev == cndev) {
-               /* the physical device is about to be closed */
-               cn_phys_is_open = 0;
-               if (cn_is_open) {
-                       if (cn_tp) {
-                               /* perform a ttyhalfclose() */
-                               /* reset session and proc group */
-                               cn_tp->t_pgrp = NULL;
-                               cn_tp->t_session = NULL;
-                       }
-                       return (0);
-               }
-       } else if (major(dev) != major(cndev)) {
-               /* the logical console is about to be closed */
-               cn_is_open = 0;
-               if (cn_phys_is_open)
-                       return (0);
-               dev = cndev;
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
+               cn_devopen(cnd, td, 0);
+       return (0);
+}
+
+static int
+cnclose(dev_t dev, int flag, int mode, struct thread *td)
+{
+       struct cn_device *cnd;
+
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+               if (cnd->cnd_vp == NULL)
+                       continue; 
+               vn_close(cnd->cnd_vp, mode, td->td_proc->p_ucred, td);
+               cnd->cnd_vp = NULL;
        }
-       if(cn_phys_close)
-               return ((*cn_phys_close)(dev, flag, mode, td));
+       cn_is_open = 0;
        return (0);
 }
 
 static int
-cnread(dev, uio, flag)
-       dev_t dev;
-       struct uio *uio;
-       int flag;
+cnread(dev_t dev, struct uio *uio, int flag)
 {
+       struct cn_device *cnd;
 
-       if (cn_tab == NULL || cn_phys_open == NULL)
+       cnd = STAILQ_FIRST(&cn_devlist);
+       if (cn_mute || CND_INVALID(cnd, curthread))
                return (0);
-       dev = cn_tab->cn_dev;
+       dev = cnd->cnd_vp->v_rdev;
        return ((*devsw(dev)->d_read)(dev, uio, flag));
 }
 
 static int
-cnwrite(dev, uio, flag)
-       dev_t dev;
-       struct uio *uio;
-       int flag;
+cnwrite(dev_t dev, struct uio *uio, int flag)
 {
+       struct cn_device *cnd;
 
-       if (cn_tab == NULL || cn_phys_open == NULL) {
-               uio->uio_resid = 0; /* dump the data */
-               return (0);
-       }
+       cnd = STAILQ_FIRST(&cn_devlist);
+       if (cn_mute || CND_INVALID(cnd, curthread))
+               goto done;
        if (constty)
                dev = constty->t_dev;
        else
-               dev = cn_tab->cn_dev;
-       log_console(uio);
-       return ((*devsw(dev)->d_write)(dev, uio, flag));
+               dev = cnd->cnd_vp->v_rdev;
+       if (dev != NULL) {
+               log_console(uio);
+               return ((*devsw(dev)->d_write)(dev, uio, flag));
+       }
+done:
+       uio->uio_resid = 0; /* dump the data */
+       return (0);
 }
 
 static int
-cnioctl(dev, cmd, data, flag, td)
-       dev_t dev;
-       u_long cmd;
-       caddr_t data;
-       int flag;
-       struct thread *td;
+cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 {
+       struct cn_device *cnd;
        int error;
 
-       if (cn_tab == NULL || cn_phys_open == NULL)
+       cnd = STAILQ_FIRST(&cn_devlist);
+       if (cn_mute || CND_INVALID(cnd, td))
                return (0);
        /*
         * Superuser can always use this to wrest control of console
@@ -382,82 +442,111 @@
                constty = NULL;
                return (0);
        }
-       dev = cn_tab->cn_dev;
-       return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
+       dev = cnd->cnd_vp->v_rdev;
+       if (dev != NULL)
+               return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
+       return (0);
 }
 
+/*
+ * XXX
+ * poll/kqfilter do not appear to be correct
+ */
 static int
-cnpoll(dev, events, td)
-       dev_t dev;
-       int events;
-       struct thread *td;
+cnpoll(dev_t dev, int events, struct thread *td)
 {
-       if ((cn_tab == NULL) || cn_mute)
-               return (1);
-
-       dev = cn_tab->cn_dev;
+       struct cn_device *cnd;
 
-       return ((*devsw(dev)->d_poll)(dev, events, td));
+       cnd = STAILQ_FIRST(&cn_devlist);
+       if (cn_mute || CND_INVALID(cnd, td))
+               return (0);
+       dev = cnd->cnd_vp->v_rdev;
+       if (dev != NULL)
+               return ((*devsw(dev)->d_poll)(dev, events, td));
+       return (0);
 }
 
 static int
-cnkqfilter(dev, kn)
-       dev_t dev;
-       struct knote *kn;
+cnkqfilter(dev_t dev, struct knote *kn)
 {
-       if ((cn_tab == NULL) || cn_mute)
-               return (1);
+       struct cn_device *cnd;
 
-       dev = cn_tab->cn_dev;
-       if (devsw(dev)->d_flags & D_KQFILTER)
+       cnd = STAILQ_FIRST(&cn_devlist);
+       if (cn_mute || CND_INVALID(cnd, curthread))
+               return (1);
+       dev = cnd->cnd_vp->v_rdev;
+       if (dev != NULL)
                return ((*devsw(dev)->d_kqfilter)(dev, kn));
        return (1);
 }
 
+/*
+ * Low level console routines.
+ */
 int
-cngetc()
+cngetc(void)
 {
        int c;
-       if ((cn_tab == NULL) || cn_mute)
+
+       if (cn_mute)
                return (-1);
-       c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
-       if (c == '\r') c = '\n'; /* console input is always ICRNL */
+       while ((c = cncheckc()) == -1)
+               ;
+       if (c == '\r')
+               c = '\n';               /* console input is always ICRNL */
        return (c);
 }
 
 int
-cncheckc()
+cncheckc(void)
 {
-       if ((cn_tab == NULL) || cn_mute)
+       struct cn_device *cnd;
+       struct consdev *cn;
+       int c;
+
+       if (cn_mute)
                return (-1);
-       return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+               cn = cnd->cnd_cn;
+               c = cn->cn_checkc(cn->cn_dev);
+               if (c != -1) {
+                       return (c);
+               }
+       }
+       return (-1);
 }
 
 void
-cnputc(c)
-       register int c;
+cnputc(int c)
 {
-       if ((cn_tab == NULL) || cn_mute)
+       struct cn_device *cnd;
+       struct consdev *cn;
+
+       if (cn_mute || c == '\0')
                return;
-       if (c) {
+       STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+               cn = cnd->cnd_cn;
                if (c == '\n')
-                       (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
-               (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+                       cn->cn_putc(cn->cn_dev, '\r');
+               cn->cn_putc(cn->cn_dev, c);
        }
 }
 
 void
-cndbctl(on)
-       int on;
+cndbctl(int on)
 {
+       struct cn_device *cnd;
+       struct consdev *cn;
        static int refcount;
 
-       if (cn_tab == NULL)
-               return;
        if (!on)
                refcount--;
-       if (refcount == 0 && cn_tab->cn_dbctl != NULL)
-               (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
+       if (refcount == 0)
+               STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
+                       cn = cnd->cnd_cn;
+                       if (cn->cn_dbctl != NULL)
+                               cn->cn_dbctl(cn->cn_dev, on);
+               }
        if (on)
                refcount++;
 }
Index: sys/conf.h
===================================================================
RCS file: /ncvs/src/sys/sys/conf.h,v
retrieving revision 1.135
diff -u -r1.135 conf.h
--- sys/conf.h  2001/10/17 18:47:12     1.135
+++ sys/conf.h  2001/10/19 16:04:51
@@ -60,6 +60,8 @@
 #define SI_NAMED       0x0004  /* make_dev{_alias} has been called */
 #define SI_CHEAPCLONE  0x0008  /* can be removed_dev'ed when vnode reclaims */
 #define SI_CHILD       0x0010  /* child of another dev_t */
+#define SI_DEVOPEN     0x0020  /* opened by device */
+#define SI_CONSOPEN    0x0040  /* opened by console */
        struct timespec si_atime;
        struct timespec si_ctime;
        struct timespec si_mtime;
Index: sys/cons.h
===================================================================
RCS file: /ncvs/src/sys/sys/cons.h,v
retrieving revision 1.25
diff -u -r1.25 cons.h
--- sys/cons.h  2001/06/13 10:58:39     1.25
+++ sys/cons.h  2001/09/27 02:25:27
@@ -78,8 +78,7 @@
 #define CN_REMOTE      3       /* serial interface with remote bit set */
 
 #ifdef _KERNEL
-extern int cons_unavail;
-extern struct consdev *cn_tab;
+extern int cons_unavail;
 
 #define CONS_DRIVER(name, probe, init, term, getc, checkc, putc, dbctl)        \
        static struct consdev name##_consdev = {                        \
@@ -88,12 +87,14 @@
        DATA_SET(cons_set, name##_consdev)
 
 /* Other kernel entry points. */
-int    cncheckc __P((void));
-int    cngetc __P((void));
-void   cninit __P((void));
-void   cninit_finish __P((void));
-void   cndbctl __P((int));
-void   cnputc __P((int));
+void   cninit(void);
+int    cnadd(struct consdev *);
+void   cnremove(struct consdev *);
+void   cnselect(struct consdev *);
+int    cncheckc(void);
+int    cngetc(void);
+void   cndbctl(int);
+void   cnputc(int);
 
 #endif /* _KERNEL */
 
Index: sys/reboot.h
===================================================================
RCS file: /ncvs/src/sys/sys/reboot.h,v
retrieving revision 1.18
diff -u -r1.18 reboot.h
--- sys/reboot.h        1999/08/28 00:51:58     1.18
+++ sys/reboot.h        2001/10/19 06:36:45
@@ -61,6 +61,7 @@
 #define        RB_GDB          0x8000  /* use GDB remote debugger instead of DDB */
 #define        RB_MUTE         0x10000 /* Come up with the console muted */
 #define        RB_SELFTEST     0x20000 /* don't boot to normal operation, do selftest 
*/
+#define        RB_MULTIPLE     0x20000000      /* Use multiple consoles */
 
 #define        RB_BOOTINFO     0x80000000      /* have `struct bootinfo *' arg */
 
Index: isa/sio.c
===================================================================
RCS file: /ncvs/src/sys/isa/sio.c,v
retrieving revision 1.347
diff -u -r1.347 sio.c
--- isa/sio.c   2001/09/29 04:49:11     1.347
+++ isa/sio.c   2001/10/20 02:24:30
@@ -2922,13 +2922,14 @@
 #else
 static cn_probe_t siocnprobe;
 static cn_init_t siocninit;
+static cn_term_t siocnterm;
 #endif
 static cn_checkc_t siocncheckc;
 static cn_getc_t siocngetc;
 static cn_putc_t siocnputc;
 
 #ifndef __alpha__
-CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc,
+CONS_DRIVER(sio, siocnprobe, siocninit, siocnterm, siocngetc, siocncheckc,
            siocnputc, NULL);
 #endif
 
@@ -3178,6 +3179,13 @@
        struct consdev  *cp;
 {
        comconsole = DEV_TO_UNIT(cp->cn_dev);
+}
+
+static void
+siocnterm(cp)
+       struct consdev  *cp;
+{
+       comconsole = -1;
 }
 
 #endif
Index: i386//i386/autoconf.c
===================================================================
RCS file: /ncvs/src/sys/i386/i386/autoconf.c,v
retrieving revision 1.158
diff -u -r1.158 autoconf.c
--- i386//i386/autoconf.c       2001/09/18 23:31:29     1.158
+++ i386//i386/autoconf.c       2001/09/22 00:38:09
@@ -176,7 +176,7 @@
 {
        int i;
 
-       cninit_finish();
+/*     cninit_finish(); */
 
        if (bootverbose) {
 
Index: boot/i386/boot2/boot2.c
===================================================================
RCS file: /ncvs/src/sys/boot/i386/boot2/boot2.c,v
retrieving revision 1.32
diff -u -r1.32 boot2.c
--- boot/i386/boot2/boot2.c     2001/07/31 19:50:09     1.32
+++ boot/i386/boot2/boot2.c     2001/10/19 06:37:45
@@ -49,7 +49,7 @@
 #define RBX_DUAL       0x1d    /* -D */
 #define RBX_PROBEKBD   0x1e    /* -P */
 
-#define RBX_MASK       0xffff
+#define RBX_MASK       0x2000ffff
 
 #define PATH_CONFIG    "/boot.config"
 #define PATH_BOOT3     "/boot/loader"
Index: boot/i386/libi386/bootinfo.c
===================================================================
RCS file: /ncvs/src/sys/boot/i386/libi386/bootinfo.c,v
retrieving revision 1.28
diff -u -r1.28 bootinfo.c
--- boot/i386/libi386/bootinfo.c        2001/02/18 10:25:41     1.28
+++ boot/i386/libi386/bootinfo.c        2001/10/19 06:30:27
@@ -88,6 +88,9 @@
                case 'd':
                    howto |= RB_KDB;
                    break;
+               case 'D':
+                   howto |= RB_MULTIPLE;
+                   break;
                case 'm':
                    howto |= RB_MUTE;
                    break;

---------------------------------- cut here ----------------------------------

# $FreeBSD$

PROG=   conscontrol
MAN=    conscontrol.8

.include <bsd.prog.mk>

---------------------------------- cut here ----------------------------------

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/sysctl.h>

static void __dead2
usage(void)
{
        const char *pname = getprogname();

        fprintf(stderr, "usage: %s [list]\n", pname);
        fprintf(stderr, "       %s mute on|off\n", pname);
        fprintf(stderr, "       %s add|delete console\n", pname);
        exit(1);
}

#define CONSBUFSIZE     32

static void
constatus(void)
{
        int mute;
        size_t len;
        char *buf, *p, *avail;

        len = sizeof(mute);
        if (sysctlbyname("kern.consmute", &mute, &len, NULL, 0) == -1)
                goto fail;

        len = 0;
alloc:
        len += CONSBUFSIZE;
        buf = malloc(len);
        if (buf == NULL)
                err(1, "Could not malloc sysctl buffer");

        if (sysctlbyname("kern.console", buf, &len, NULL, 0) == -1) {
                if (errno == ENOMEM) {
                        free(buf);
                        goto alloc;
                }
                goto fail;
        }
        avail = strchr(buf, '/');
        p = avail;
        *avail++ = '\0';
        if (p != buf)
                *--p = '\0';                    /* remove trailing ',' */
        p = avail + strlen(avail);
        if (p != avail)
                *--p = '\0';                    /* remove trailing ',' */
        printf("Configured: %s\n", buf);
        printf(" Available: %s\n", avail);
        printf("    Muting: %s\n", mute ? "on" : "off");
        free(buf);
        return;
fail:
        err(1, "Could not get console information");
}

static void
consmute(const char *onoff)
{
        int mute;
        size_t len;

        if (strcmp(onoff, "on") == 0)
                mute = 1;
        else if (strcmp(onoff, "off") == 0)
                mute = 0;
        else
                usage();
        len = sizeof(mute);
        if (sysctlbyname("kern.consmute", NULL, NULL, &mute, len) == -1)
                err(1, "Could not change console muting");
}

static void
consadd(char *devname)
{
        size_t len;

        len = strlen(devname);
        if (sysctlbyname("kern.console", NULL, NULL, devname, len) == -1)
                err(1, "Could not add %s as a console", devname);
}

#define MAXDEVNAME      32

static void
consdel(const char *devname)
{
        char buf[MAXDEVNAME];
        size_t len;

        snprintf(buf, MAXDEVNAME, "-%s", devname);
        len = strlen(buf);
        if (sysctlbyname("kern.console", NULL, NULL, &buf, len) == -1)
                err(1, "Could not remove %s as a console", devname);
}

int
main(int argc, char **argv)
{

        if (argc < 2 || strcmp(argv[1], "list") == 0)
                goto done;
        if (argc < 3)
                usage();
        if (strcmp(argv[1], "mute") == 0)
                consmute(argv[2]);
        else if (strcmp(argv[1], "add") == 0)
                consadd(argv[2]);
        else if (strcmp(argv[1], "delete") == 0)
                consdel(argv[2]);
        else
                usage();
done:
        constatus();
}

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to