kern_cons.c revision 87620
14Srgrimes/*
24Srgrimes * Copyright (c) 1988 University of Utah.
34Srgrimes * Copyright (c) 1991 The Regents of the University of California.
44Srgrimes * All rights reserved.
54Srgrimes *
64Srgrimes * This code is derived from software contributed to Berkeley by
74Srgrimes * the Systems Programming Group of the University of Utah Computer
84Srgrimes * Science Department.
94Srgrimes *
104Srgrimes * Redistribution and use in source and binary forms, with or without
114Srgrimes * modification, are permitted provided that the following conditions
124Srgrimes * are met:
134Srgrimes * 1. Redistributions of source code must retain the above copyright
144Srgrimes *    notice, this list of conditions and the following disclaimer.
154Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
164Srgrimes *    notice, this list of conditions and the following disclaimer in the
174Srgrimes *    documentation and/or other materials provided with the distribution.
184Srgrimes * 3. All advertising materials mentioning features or use of this software
194Srgrimes *    must display the following acknowledgement:
204Srgrimes *	This product includes software developed by the University of
214Srgrimes *	California, Berkeley and its contributors.
224Srgrimes * 4. Neither the name of the University nor the names of its contributors
234Srgrimes *    may be used to endorse or promote products derived from this software
244Srgrimes *    without specific prior written permission.
254Srgrimes *
264Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
274Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
284Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
294Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
304Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
314Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
324Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
334Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
344Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
354Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
364Srgrimes * SUCH DAMAGE.
374Srgrimes *
38620Srgrimes *	from: @(#)cons.c	7.2 (Berkeley) 5/9/91
3950477Speter * $FreeBSD: head/sys/kern/tty_cons.c 87620 2001-12-10 20:02:22Z guido $
404Srgrimes */
414Srgrimes
422056Swollman#include <sys/param.h>
431549Srgrimes#include <sys/systm.h>
445764Sbde#include <sys/conf.h>
4556525Sbde#include <sys/cons.h>
4685448Sjlemon#include <sys/fcntl.h>
4712675Sjulian#include <sys/kernel.h>
4885373Sjlemon#include <sys/malloc.h>
4985373Sjlemon#include <sys/namei.h>
5069929Sobrien#include <sys/proc.h>
5185373Sjlemon#include <sys/queue.h>
5218951Sjulian#include <sys/reboot.h>
5312701Sphk#include <sys/sysctl.h>
542056Swollman#include <sys/tty.h>
5534924Sbde#include <sys/uio.h>
5685373Sjlemon#include <sys/vnode.h>
574Srgrimes
5887620Sguido#include <ddb/ddb.h>
5987620Sguido
6012701Sphk#include <machine/cpu.h>
614Srgrimes
6212675Sjulianstatic	d_open_t	cnopen;
6312675Sjulianstatic	d_close_t	cnclose;
6412675Sjulianstatic	d_read_t	cnread;
6512675Sjulianstatic	d_write_t	cnwrite;
6612675Sjulianstatic	d_ioctl_t	cnioctl;
6729368Speterstatic	d_poll_t	cnpoll;
6872521Sjlemonstatic	d_kqfilter_t	cnkqfilter;
6912675Sjulian
7038485Sbde#define	CDEV_MAJOR	0
7147625Sphkstatic struct cdevsw cn_cdevsw = {
7247625Sphk	/* open */	cnopen,
7347625Sphk	/* close */	cnclose,
7447625Sphk	/* read */	cnread,
7547625Sphk	/* write */	cnwrite,
7647625Sphk	/* ioctl */	cnioctl,
7747625Sphk	/* poll */	cnpoll,
7847625Sphk	/* mmap */	nommap,
7947625Sphk	/* strategy */	nostrategy,
8047625Sphk	/* name */	"console",
8147625Sphk	/* maj */	CDEV_MAJOR,
8247625Sphk	/* dump */	nodump,
8347625Sphk	/* psize */	nopsize,
8472521Sjlemon	/* flags */	D_TTY | D_KQFILTER,
8572521Sjlemon	/* kqfilter */	cnkqfilter,
8638485Sbde};
8712675Sjulian
8885373Sjlemonstruct cn_device {
8985373Sjlemon	STAILQ_ENTRY(cn_device) cnd_next;
9085373Sjlemon	char		cnd_name[16];
9185373Sjlemon	struct		vnode *cnd_vp;
9285373Sjlemon	struct		consdev *cnd_cn;
9385373Sjlemon};
9485373Sjlemon
9585373Sjlemon#define CNDEVPATHMAX	32
9685373Sjlemon#define CNDEVTAB_SIZE	4
9785373Sjlemonstatic struct cn_device cn_devtab[CNDEVTAB_SIZE];
9885373Sjlemonstatic STAILQ_HEAD(, cn_device) cn_devlist =
9985373Sjlemon    STAILQ_HEAD_INITIALIZER(cn_devlist);
10085373Sjlemon
10185373Sjlemon#define CND_INVALID(cnd, td) 						\
10285373Sjlemon	(cnd == NULL || cnd->cnd_vp == NULL ||				\
10385373Sjlemon	    (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
10485373Sjlemon
10549049Syokotastatic udev_t	cn_udev_t;
10641612SeivindSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
10749049Syokota	&cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
10827982Sjulian
1097680Sjoergint	cons_unavail = 0;	/* XXX:
1107680Sjoerg				 * physical console not available for
1117680Sjoerg				 * input (i.e., it is in graphics mode)
1127680Sjoerg				 */
11385373Sjlemonstatic int cn_mute;
11485373Sjlemonstatic int openflag;			/* how /dev/console was opened */
11585373Sjlemonstatic int cn_is_open;
11656525Sbdestatic dev_t cn_devfsdev;		/* represents the device private info */
11787620Sguidostatic u_char console_pausing;		/* pause after each line during probe */
11887620Sguidostatic char *console_pausestr=
11987620Sguido"<pause; press any key to proceed to next line or '.' to end pause mode>";
1205764Sbde
12185448Sjlemonvoid	cndebug(char *);
12285448Sjlemon
12355823SyokotaCONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
12478161SpeterSET_DECLARE(cons_set, struct consdev);
12542373Syokota
126798Swollmanvoid
12785373Sjlemoncninit(void)
1284Srgrimes{
12985373Sjlemon	struct consdev *best_cn, *cn, **list;
1304Srgrimes
1314Srgrimes	/*
13218951Sjulian	 * Check if we should mute the console (for security reasons perhaps)
13318951Sjulian	 * It can be changes dynamically using sysctl kern.consmute
13418951Sjulian	 * once we are up and going.
13518951Sjulian	 *
13618951Sjulian	 */
13718951Sjulian        cn_mute = ((boothowto & (RB_MUTE
13818951Sjulian			|RB_SINGLE
13918951Sjulian			|RB_VERBOSE
14018951Sjulian			|RB_ASKNAME
14118951Sjulian			|RB_CONFIG)) == RB_MUTE);
14285373Sjlemon
14318951Sjulian	/*
14485373Sjlemon	 * Find the first console with the highest priority.
1454Srgrimes	 */
14685373Sjlemon	best_cn = NULL;
14785373Sjlemon	SET_FOREACH(list, cons_set) {
14885373Sjlemon		cn = *list;
14985373Sjlemon		if (cn->cn_probe == NULL)
15085373Sjlemon			continue;
15185373Sjlemon		cn->cn_probe(cn);
15285373Sjlemon		if (cn->cn_pri == CN_DEAD)
15385373Sjlemon			continue;
15485373Sjlemon		if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
15585373Sjlemon			best_cn = cn;
15685373Sjlemon		if (boothowto & RB_MULTIPLE) {
15785373Sjlemon			/*
15885373Sjlemon			 * Initialize console, and attach to it.
15985373Sjlemon			 */
16085373Sjlemon			cnadd(cn);
16185373Sjlemon			cn->cn_init(cn);
16285373Sjlemon		}
16385373Sjlemon	}
16485373Sjlemon	if (best_cn == NULL)
1654Srgrimes		return;
16685373Sjlemon	if ((boothowto & RB_MULTIPLE) == 0) {
16785373Sjlemon		cnadd(best_cn);
16885373Sjlemon		best_cn->cn_init(best_cn);
16910665Sbde	}
17087620Sguido	if (boothowto & RB_PAUSE)
17187620Sguido		console_pausing = 1;
1724Srgrimes	/*
17385373Sjlemon	 * Make the best console the preferred console.
17410665Sbde	 */
17585373Sjlemon	cnselect(best_cn);
17685373Sjlemon}
17785373Sjlemon
17887620Sguidovoid
17987620Sguidocninit_finish()
18087620Sguido{
18187620Sguido	console_pausing = 0;
18287620Sguido}
18387620Sguido
18485373Sjlemon/* add a new physical console to back the virtual console */
18585373Sjlemonint
18685373Sjlemoncnadd(struct consdev *cn)
18785373Sjlemon{
18885373Sjlemon	struct cn_device *cnd;
18985373Sjlemon	int i;
19085373Sjlemon
19185373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
19285373Sjlemon		if (cnd->cnd_cn == cn)
19385373Sjlemon			return (0);
19485373Sjlemon	for (i = 0; i < CNDEVTAB_SIZE; i++) {
19585373Sjlemon		cnd = &cn_devtab[i];
19685373Sjlemon		if (cnd->cnd_cn == NULL)
19785373Sjlemon			break;
19848104Syokota	}
19985373Sjlemon	if (cnd->cnd_cn != NULL)
20085373Sjlemon		return (ENOMEM);
20185373Sjlemon	cnd->cnd_cn = cn;
20285373Sjlemon	STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
20385373Sjlemon	return (0);
20410665Sbde}
20510665Sbde
20610665Sbdevoid
20785373Sjlemoncnremove(struct consdev *cn)
20810665Sbde{
20985373Sjlemon	struct cn_device *cnd;
21010665Sbde
21185373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
21285373Sjlemon		if (cnd->cnd_cn != cn)
21385373Sjlemon			continue;
21485373Sjlemon		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
21585373Sjlemon		if (cnd->cnd_vp != NULL)
21685373Sjlemon			vn_close(cnd->cnd_vp, openflag, NOCRED, NULL);
21785373Sjlemon		cnd->cnd_vp = NULL;
21885373Sjlemon		cnd->cnd_cn = NULL;
21985373Sjlemon		cnd->cnd_name[0] = '\0';
22085373Sjlemon#if 0
22185373Sjlemon		/*
22285373Sjlemon		 * XXX
22385373Sjlemon		 * syscons gets really confused if console resources are
22485373Sjlemon		 * freed after the system has initialized.
22585373Sjlemon		 */
22685373Sjlemon		if (cn->cn_term != NULL)
22785373Sjlemon			cn->cn_term(cn);
22885373Sjlemon#endif
22910665Sbde		return;
23056582Sbde	}
2314Srgrimes}
2324Srgrimes
23385373Sjlemonvoid
23485373Sjlemoncnselect(struct consdev *cn)
23527982Sjulian{
23685373Sjlemon	struct cn_device *cnd;
23727982Sjulian
23885373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
23985373Sjlemon		if (cnd->cnd_cn != cn)
24085373Sjlemon			continue;
24185373Sjlemon		if (cnd == STAILQ_FIRST(&cn_devlist))
24285373Sjlemon			return;
24385373Sjlemon		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
24485373Sjlemon		STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
24527982Sjulian		return;
24685373Sjlemon	}
24785373Sjlemon}
24827982Sjulian
24985373Sjlemonvoid
25085373Sjlemoncndebug(char *str)
25185373Sjlemon{
25285373Sjlemon	int i, len;
25385373Sjlemon
25485373Sjlemon	len = strlen(str);
25585373Sjlemon	cnputc('>'); cnputc('>'); cnputc('>'); cnputc(' ');
25685373Sjlemon	for (i = 0; i < len; i++)
25785373Sjlemon		cnputc(str[i]);
25885373Sjlemon	cnputc('\n');
25985373Sjlemon}
26085373Sjlemon
26185373Sjlemonstatic int
26285373Sjlemonsysctl_kern_console(SYSCTL_HANDLER_ARGS)
26385373Sjlemon{
26485373Sjlemon	struct cn_device *cnd;
26585373Sjlemon	struct consdev *cp, **list;
26685373Sjlemon	char *name, *p;
26785373Sjlemon	int delete, len, error;
26885373Sjlemon
26985373Sjlemon	len = 2;
27085373Sjlemon	SET_FOREACH(list, cons_set) {
27185373Sjlemon		cp = *list;
27285373Sjlemon		if (cp->cn_dev != NULL)
27385373Sjlemon			len += strlen(devtoname(cp->cn_dev)) + 1;
27456582Sbde	}
27585373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
27685373Sjlemon		len += strlen(devtoname(cnd->cnd_cn->cn_dev)) + 1;
27785373Sjlemon	len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX;
27885373Sjlemon	MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO);
27985373Sjlemon	p = name;
28085373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
28185373Sjlemon		p += sprintf(p, "%s,", devtoname(cnd->cnd_cn->cn_dev));
28285373Sjlemon	*p++ = '/';
28385373Sjlemon	SET_FOREACH(list, cons_set) {
28485373Sjlemon		cp = *list;
28585373Sjlemon		if (cp->cn_dev != NULL)
28685373Sjlemon			p += sprintf(p, "%s,", devtoname(cp->cn_dev));
28785373Sjlemon	}
28885373Sjlemon	error = sysctl_handle_string(oidp, name, len, req);
28985373Sjlemon	if (error == 0 && req->newptr != NULL) {
29085373Sjlemon		p = name;
29185373Sjlemon		error = ENXIO;
29285373Sjlemon		delete = 0;
29385373Sjlemon		if (*p == '-') {
29485373Sjlemon			delete = 1;
29585373Sjlemon			p++;
29685373Sjlemon		}
29785373Sjlemon		SET_FOREACH(list, cons_set) {
29885373Sjlemon			cp = *list;
29985373Sjlemon			if (cp->cn_dev == NULL ||
30085373Sjlemon			    strcmp(p, devtoname(cp->cn_dev)) != 0)
30185373Sjlemon				continue;
30285373Sjlemon			if (delete) {
30385373Sjlemon				cnremove(cp);
30485373Sjlemon				error = 0;
30585373Sjlemon			} else {
30685373Sjlemon				error = cnadd(cp);
30785373Sjlemon				if (error == 0)
30885373Sjlemon					cnselect(cp);
30985373Sjlemon			}
31085373Sjlemon			break;
31185373Sjlemon		}
31285373Sjlemon	}
31385373Sjlemon	FREE(name, M_TEMP);
31485373Sjlemon	return (error);
31527982Sjulian}
31627982Sjulian
31785373SjlemonSYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW,
31885373Sjlemon	0, 0, sysctl_kern_console, "A", "Console device control");
31985373Sjlemon
32027982Sjulian/*
32127982Sjulian * User has changed the state of the console muting.
32227982Sjulian * This may require us to open or close the device in question.
32327982Sjulian */
32412675Sjulianstatic int
32562573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
32627982Sjulian{
32727982Sjulian	int error;
32827982Sjulian	int ocn_mute;
32927982Sjulian
33027982Sjulian	ocn_mute = cn_mute;
33127982Sjulian	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
33285373Sjlemon	if (error != 0 || req->newptr == NULL)
33385373Sjlemon		return (error);
33485373Sjlemon	if (ocn_mute && !cn_mute && cn_is_open)
33585373Sjlemon		error = cnopen(NODEV, openflag, 0, curthread);
33685373Sjlemon	else if (!ocn_mute && cn_mute && cn_is_open) {
33785373Sjlemon		error = cnclose(NODEV, openflag, 0, curthread);
33885373Sjlemon		cn_is_open = 1;		/* XXX hack */
33927982Sjulian	}
34027982Sjulian	return (error);
34127982Sjulian}
34227982Sjulian
34327982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
34485373Sjlemon	0, sizeof(cn_mute), sysctl_kern_consmute, "I", "");
34527982Sjulian
34627982Sjulianstatic int
34785373Sjlemoncn_devopen(struct cn_device *cnd, struct thread *td, int forceopen)
34885373Sjlemon{
34985373Sjlemon	char path[CNDEVPATHMAX];
35085884Sjlemon	struct nameidata nd;
35185884Sjlemon	struct vnode *vp;
3524Srgrimes	dev_t dev;
35385373Sjlemon	int error;
3541007Sdg
35585884Sjlemon	if ((vp = cnd->cnd_vp) != NULL) {
35685884Sjlemon		if (!forceopen && vp->v_type != VBAD) {
35785884Sjlemon			dev = vp->v_rdev;
35885373Sjlemon			return ((*devsw(dev)->d_open)(dev, openflag, 0, td));
35927982Sjulian		}
36085373Sjlemon		cnd->cnd_vp = NULL;
36185884Sjlemon		vn_close(vp, openflag, td->td_proc->p_ucred, td);
3625764Sbde	}
36385373Sjlemon	if (cnd->cnd_name[0] == '\0')
36485373Sjlemon		strncpy(cnd->cnd_name, devtoname(cnd->cnd_cn->cn_dev),
36585373Sjlemon		    sizeof(cnd->cnd_name));
36685373Sjlemon	snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_name);
36785373Sjlemon	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
36885373Sjlemon	error = vn_open(&nd, &openflag, 0);
36985373Sjlemon	if (error == 0) {
37085373Sjlemon		NDFREE(&nd, NDF_ONLY_PNBUF);
37185373Sjlemon		VOP_UNLOCK(nd.ni_vp, 0, td);
37285373Sjlemon		if (nd.ni_vp->v_type == VCHR)
37385373Sjlemon			cnd->cnd_vp = nd.ni_vp;
37485373Sjlemon		else
37585373Sjlemon			vn_close(nd.ni_vp, openflag, td->td_proc->p_ucred, td);
37685373Sjlemon	}
37785373Sjlemon	return (cnd->cnd_vp != NULL);
3784Srgrimes}
3798876Srgrimes
38012675Sjulianstatic int
38185373Sjlemoncnopen(dev_t dev, int flag, int mode, struct thread *td)
3824Srgrimes{
38385373Sjlemon	struct cn_device *cnd;
3841007Sdg
38585448Sjlemon	openflag = flag | FWRITE;	/* XXX */
38685373Sjlemon	cn_is_open = 1;			/* console is logically open */
38785373Sjlemon	if (cn_mute)
3884Srgrimes		return (0);
38985373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
39085373Sjlemon		cn_devopen(cnd, td, 0);
39185373Sjlemon	return (0);
39285373Sjlemon}
39385373Sjlemon
39485373Sjlemonstatic int
39585373Sjlemoncnclose(dev_t dev, int flag, int mode, struct thread *td)
39685373Sjlemon{
39785373Sjlemon	struct cn_device *cnd;
39885458Sjlemon	struct vnode *vp;
39985373Sjlemon
40085373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
40185458Sjlemon		if ((vp = cnd->cnd_vp) == NULL)
40285373Sjlemon			continue;
40385373Sjlemon		cnd->cnd_vp = NULL;
40485458Sjlemon		vn_close(vp, openflag, td->td_proc->p_ucred, td);
4055764Sbde	}
40685373Sjlemon	cn_is_open = 0;
40727982Sjulian	return (0);
4084Srgrimes}
4098876Srgrimes
41012675Sjulianstatic int
41185373Sjlemoncnread(dev_t dev, struct uio *uio, int flag)
4124Srgrimes{
41385373Sjlemon	struct cn_device *cnd;
41456582Sbde
41585373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
41685373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
4174Srgrimes		return (0);
41885373Sjlemon	dev = cnd->cnd_vp->v_rdev;
41946676Sphk	return ((*devsw(dev)->d_read)(dev, uio, flag));
4204Srgrimes}
4218876Srgrimes
42212675Sjulianstatic int
42385373Sjlemoncnwrite(dev_t dev, struct uio *uio, int flag)
4244Srgrimes{
42585373Sjlemon	struct cn_device *cnd;
42656582Sbde
42785373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
42885373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
42985373Sjlemon		goto done;
4301021Sdg	if (constty)
4314Srgrimes		dev = constty->t_dev;
4324Srgrimes	else
43385373Sjlemon		dev = cnd->cnd_vp->v_rdev;
43485373Sjlemon	if (dev != NULL) {
43585373Sjlemon		log_console(uio);
43685373Sjlemon		return ((*devsw(dev)->d_write)(dev, uio, flag));
43785373Sjlemon	}
43885373Sjlemondone:
43985373Sjlemon	uio->uio_resid = 0; /* dump the data */
44085373Sjlemon	return (0);
4414Srgrimes}
4428876Srgrimes
44312675Sjulianstatic int
44485373Sjlemoncnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
4454Srgrimes{
44685373Sjlemon	struct cn_device *cnd;
4474Srgrimes	int error;
4484Srgrimes
44985373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
45085373Sjlemon	if (cn_mute || CND_INVALID(cnd, td))
4514Srgrimes		return (0);
4524Srgrimes	/*
4534Srgrimes	 * Superuser can always use this to wrest control of console
4544Srgrimes	 * output from the "virtual" console.
4554Srgrimes	 */
4564Srgrimes	if (cmd == TIOCCONS && constty) {
45783366Sjulian		error = suser_td(td);
4584Srgrimes		if (error)
4594Srgrimes			return (error);
4604Srgrimes		constty = NULL;
4614Srgrimes		return (0);
4624Srgrimes	}
46385373Sjlemon	dev = cnd->cnd_vp->v_rdev;
46485373Sjlemon	if (dev != NULL)
46585373Sjlemon		return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
46685373Sjlemon	return (0);
4674Srgrimes}
4684Srgrimes
46985373Sjlemon/*
47085373Sjlemon * XXX
47185373Sjlemon * poll/kqfilter do not appear to be correct
47285373Sjlemon */
47312675Sjulianstatic int
47485373Sjlemoncnpoll(dev_t dev, int events, struct thread *td)
4754Srgrimes{
47685373Sjlemon	struct cn_device *cnd;
4776712Spst
47885373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
47985373Sjlemon	if (cn_mute || CND_INVALID(cnd, td))
48085373Sjlemon		return (0);
48185373Sjlemon	dev = cnd->cnd_vp->v_rdev;
48285373Sjlemon	if (dev != NULL)
48385373Sjlemon		return ((*devsw(dev)->d_poll)(dev, events, td));
48485373Sjlemon	return (0);
4854Srgrimes}
4864Srgrimes
48772521Sjlemonstatic int
48885373Sjlemoncnkqfilter(dev_t dev, struct knote *kn)
48972521Sjlemon{
49085373Sjlemon	struct cn_device *cnd;
49185373Sjlemon
49285373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
49385373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
49472521Sjlemon		return (1);
49585373Sjlemon	dev = cnd->cnd_vp->v_rdev;
49685373Sjlemon	if (dev != NULL)
49772521Sjlemon		return ((*devsw(dev)->d_kqfilter)(dev, kn));
49872521Sjlemon	return (1);
49972521Sjlemon}
50072521Sjlemon
50185373Sjlemon/*
50285373Sjlemon * Low level console routines.
50385373Sjlemon */
504798Swollmanint
50585373Sjlemoncngetc(void)
5064Srgrimes{
5075160Sjoerg	int c;
50885373Sjlemon
50985373Sjlemon	if (cn_mute)
51019268Sjulian		return (-1);
51185373Sjlemon	while ((c = cncheckc()) == -1)
51285373Sjlemon		;
51385373Sjlemon	if (c == '\r')
51485373Sjlemon		c = '\n';		/* console input is always ICRNL */
5155160Sjoerg	return (c);
5164Srgrimes}
5174Srgrimes
5183728Sphkint
51985373Sjlemoncncheckc(void)
5203728Sphk{
52185373Sjlemon	struct cn_device *cnd;
52285373Sjlemon	struct consdev *cn;
52385373Sjlemon	int c;
52485373Sjlemon
52585373Sjlemon	if (cn_mute)
52618287Sbde		return (-1);
52785373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
52885373Sjlemon		cn = cnd->cnd_cn;
52985373Sjlemon		c = cn->cn_checkc(cn->cn_dev);
53085373Sjlemon		if (c != -1) {
53185373Sjlemon			return (c);
53285373Sjlemon		}
53385373Sjlemon	}
53485373Sjlemon	return (-1);
5353728Sphk}
5363728Sphk
537798Swollmanvoid
53885373Sjlemoncnputc(int c)
5394Srgrimes{
54085373Sjlemon	struct cn_device *cnd;
54185373Sjlemon	struct consdev *cn;
54287620Sguido	char *cp;
54385373Sjlemon
54485373Sjlemon	if (cn_mute || c == '\0')
5454Srgrimes		return;
54685373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
54785373Sjlemon		cn = cnd->cnd_cn;
5484Srgrimes		if (c == '\n')
54985373Sjlemon			cn->cn_putc(cn->cn_dev, '\r');
55085373Sjlemon		cn->cn_putc(cn->cn_dev, c);
5514Srgrimes	}
55287620Sguido	if (console_pausing && !db_active && (c == '\n')) {
55387620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
55487620Sguido			cnputc(*cp);
55587620Sguido		if (cngetc() == '.')
55687620Sguido			console_pausing = 0;
55787620Sguido		cnputc('\r');
55887620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
55987620Sguido			cnputc(' ');
56087620Sguido		cnputc('\r');
56187620Sguido	}
5624Srgrimes}
5634Srgrimes
56455823Syokotavoid
56585373Sjlemoncndbctl(int on)
56655823Syokota{
56785373Sjlemon	struct cn_device *cnd;
56885373Sjlemon	struct consdev *cn;
56955823Syokota	static int refcount;
57055823Syokota
57155823Syokota	if (!on)
57255823Syokota		refcount--;
57385373Sjlemon	if (refcount == 0)
57485373Sjlemon		STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
57585373Sjlemon			cn = cnd->cnd_cn;
57685373Sjlemon			if (cn->cn_dbctl != NULL)
57785373Sjlemon				cn->cn_dbctl(cn->cn_dev, on);
57885373Sjlemon		}
57955823Syokota	if (on)
58055823Syokota		refcount++;
58155823Syokota}
58255823Syokota
58312675Sjulianstatic void
58412675Sjuliancn_drvinit(void *unused)
58512517Sjulian{
58612517Sjulian
58756525Sbde	cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
58856525Sbde	    "console");
58912517Sjulian}
59012517Sjulian
59112517SjulianSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
592