Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Oct 2001 15:33:43 -0500
From:      Jonathan Lemon <jlemon@flugsvamp.com>
To:        hackers@freebsd.org
Subject:   patch for review: multiple console support
Message-ID:  <20011020153343.U75389@prism.flugsvamp.com>

next in thread | raw e-mail | index | archive | help
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 majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011020153343.U75389>