kern_cons.c revision 111815
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 111815 2003-03-03 12:15:54Z phk $
404Srgrimes */
414Srgrimes
4287649Sguido#include "opt_ddb.h"
4387649Sguido
442056Swollman#include <sys/param.h>
451549Srgrimes#include <sys/systm.h>
465764Sbde#include <sys/conf.h>
4756525Sbde#include <sys/cons.h>
4885448Sjlemon#include <sys/fcntl.h>
4912675Sjulian#include <sys/kernel.h>
5085373Sjlemon#include <sys/malloc.h>
5185373Sjlemon#include <sys/namei.h>
5269929Sobrien#include <sys/proc.h>
5385373Sjlemon#include <sys/queue.h>
5418951Sjulian#include <sys/reboot.h>
5512701Sphk#include <sys/sysctl.h>
562056Swollman#include <sys/tty.h>
5734924Sbde#include <sys/uio.h>
5885373Sjlemon#include <sys/vnode.h>
594Srgrimes
6087620Sguido#include <ddb/ddb.h>
6187620Sguido
6212701Sphk#include <machine/cpu.h>
634Srgrimes
6412675Sjulianstatic	d_open_t	cnopen;
6512675Sjulianstatic	d_close_t	cnclose;
6612675Sjulianstatic	d_read_t	cnread;
6712675Sjulianstatic	d_write_t	cnwrite;
6812675Sjulianstatic	d_ioctl_t	cnioctl;
6929368Speterstatic	d_poll_t	cnpoll;
7072521Sjlemonstatic	d_kqfilter_t	cnkqfilter;
7112675Sjulian
7238485Sbde#define	CDEV_MAJOR	0
7347625Sphkstatic struct cdevsw cn_cdevsw = {
74111815Sphk	.d_open =	cnopen,
75111815Sphk	.d_close =	cnclose,
76111815Sphk	.d_read =	cnread,
77111815Sphk	.d_write =	cnwrite,
78111815Sphk	.d_ioctl =	cnioctl,
79111815Sphk	.d_poll =	cnpoll,
80111815Sphk	.d_name =	"console",
81111815Sphk	.d_maj =	CDEV_MAJOR,
82111815Sphk	.d_flags =	D_TTY | D_KQFILTER,
83111815Sphk	.d_kqfilter =	cnkqfilter,
8438485Sbde};
8512675Sjulian
8685373Sjlemonstruct cn_device {
8785373Sjlemon	STAILQ_ENTRY(cn_device) cnd_next;
8885373Sjlemon	char		cnd_name[16];
8985373Sjlemon	struct		vnode *cnd_vp;
9085373Sjlemon	struct		consdev *cnd_cn;
9185373Sjlemon};
9285373Sjlemon
9385373Sjlemon#define CNDEVPATHMAX	32
9485373Sjlemon#define CNDEVTAB_SIZE	4
9585373Sjlemonstatic struct cn_device cn_devtab[CNDEVTAB_SIZE];
9685373Sjlemonstatic STAILQ_HEAD(, cn_device) cn_devlist =
9785373Sjlemon    STAILQ_HEAD_INITIALIZER(cn_devlist);
9885373Sjlemon
9985373Sjlemon#define CND_INVALID(cnd, td) 						\
10085373Sjlemon	(cnd == NULL || cnd->cnd_vp == NULL ||				\
10185373Sjlemon	    (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
10285373Sjlemon
10349049Syokotastatic udev_t	cn_udev_t;
10441612SeivindSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
10549049Syokota	&cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
10627982Sjulian
1077680Sjoergint	cons_unavail = 0;	/* XXX:
1087680Sjoerg				 * physical console not available for
1097680Sjoerg				 * input (i.e., it is in graphics mode)
1107680Sjoerg				 */
11185373Sjlemonstatic int cn_mute;
11285373Sjlemonstatic int openflag;			/* how /dev/console was opened */
11385373Sjlemonstatic int cn_is_open;
11487620Sguidostatic u_char console_pausing;		/* pause after each line during probe */
11587620Sguidostatic char *console_pausestr=
11687620Sguido"<pause; press any key to proceed to next line or '.' to end pause mode>";
1175764Sbde
11885448Sjlemonvoid	cndebug(char *);
11985448Sjlemon
12055823SyokotaCONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
12178161SpeterSET_DECLARE(cons_set, struct consdev);
12242373Syokota
123798Swollmanvoid
12485373Sjlemoncninit(void)
1254Srgrimes{
12685373Sjlemon	struct consdev *best_cn, *cn, **list;
1274Srgrimes
1284Srgrimes	/*
12918951Sjulian	 * Check if we should mute the console (for security reasons perhaps)
13018951Sjulian	 * It can be changes dynamically using sysctl kern.consmute
13118951Sjulian	 * once we are up and going.
13218951Sjulian	 *
13318951Sjulian	 */
13418951Sjulian        cn_mute = ((boothowto & (RB_MUTE
13518951Sjulian			|RB_SINGLE
13618951Sjulian			|RB_VERBOSE
13718951Sjulian			|RB_ASKNAME
13818951Sjulian			|RB_CONFIG)) == RB_MUTE);
13985373Sjlemon
14018951Sjulian	/*
14185373Sjlemon	 * Find the first console with the highest priority.
1424Srgrimes	 */
14385373Sjlemon	best_cn = NULL;
14485373Sjlemon	SET_FOREACH(list, cons_set) {
14585373Sjlemon		cn = *list;
146101436Sjake		cnremove(cn);
14785373Sjlemon		if (cn->cn_probe == NULL)
14885373Sjlemon			continue;
14985373Sjlemon		cn->cn_probe(cn);
15085373Sjlemon		if (cn->cn_pri == CN_DEAD)
15185373Sjlemon			continue;
15285373Sjlemon		if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
15385373Sjlemon			best_cn = cn;
15485373Sjlemon		if (boothowto & RB_MULTIPLE) {
15585373Sjlemon			/*
15685373Sjlemon			 * Initialize console, and attach to it.
15785373Sjlemon			 */
15885373Sjlemon			cnadd(cn);
15985373Sjlemon			cn->cn_init(cn);
16085373Sjlemon		}
16185373Sjlemon	}
16285373Sjlemon	if (best_cn == NULL)
1634Srgrimes		return;
16485373Sjlemon	if ((boothowto & RB_MULTIPLE) == 0) {
16585373Sjlemon		cnadd(best_cn);
16685373Sjlemon		best_cn->cn_init(best_cn);
16710665Sbde	}
16887620Sguido	if (boothowto & RB_PAUSE)
16987620Sguido		console_pausing = 1;
1704Srgrimes	/*
17185373Sjlemon	 * Make the best console the preferred console.
17210665Sbde	 */
17385373Sjlemon	cnselect(best_cn);
17485373Sjlemon}
17585373Sjlemon
17687620Sguidovoid
17787620Sguidocninit_finish()
17887620Sguido{
17987620Sguido	console_pausing = 0;
18087620Sguido}
18187620Sguido
18285373Sjlemon/* add a new physical console to back the virtual console */
18385373Sjlemonint
18485373Sjlemoncnadd(struct consdev *cn)
18585373Sjlemon{
18685373Sjlemon	struct cn_device *cnd;
18785373Sjlemon	int i;
18885373Sjlemon
18985373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
19085373Sjlemon		if (cnd->cnd_cn == cn)
19185373Sjlemon			return (0);
19285373Sjlemon	for (i = 0; i < CNDEVTAB_SIZE; i++) {
19385373Sjlemon		cnd = &cn_devtab[i];
19485373Sjlemon		if (cnd->cnd_cn == NULL)
19585373Sjlemon			break;
19648104Syokota	}
19785373Sjlemon	if (cnd->cnd_cn != NULL)
19885373Sjlemon		return (ENOMEM);
19985373Sjlemon	cnd->cnd_cn = cn;
20085373Sjlemon	STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
20185373Sjlemon	return (0);
20210665Sbde}
20310665Sbde
20410665Sbdevoid
20585373Sjlemoncnremove(struct consdev *cn)
20610665Sbde{
20785373Sjlemon	struct cn_device *cnd;
20810665Sbde
20985373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
21085373Sjlemon		if (cnd->cnd_cn != cn)
21185373Sjlemon			continue;
21285373Sjlemon		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
21385373Sjlemon		if (cnd->cnd_vp != NULL)
21485373Sjlemon			vn_close(cnd->cnd_vp, openflag, NOCRED, NULL);
21585373Sjlemon		cnd->cnd_vp = NULL;
21685373Sjlemon		cnd->cnd_cn = NULL;
21785373Sjlemon		cnd->cnd_name[0] = '\0';
21885373Sjlemon#if 0
21985373Sjlemon		/*
22085373Sjlemon		 * XXX
22185373Sjlemon		 * syscons gets really confused if console resources are
22285373Sjlemon		 * freed after the system has initialized.
22385373Sjlemon		 */
22485373Sjlemon		if (cn->cn_term != NULL)
22585373Sjlemon			cn->cn_term(cn);
22685373Sjlemon#endif
22710665Sbde		return;
22856582Sbde	}
2294Srgrimes}
2304Srgrimes
23185373Sjlemonvoid
23285373Sjlemoncnselect(struct consdev *cn)
23327982Sjulian{
23485373Sjlemon	struct cn_device *cnd;
23527982Sjulian
23685373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
23785373Sjlemon		if (cnd->cnd_cn != cn)
23885373Sjlemon			continue;
23985373Sjlemon		if (cnd == STAILQ_FIRST(&cn_devlist))
24085373Sjlemon			return;
24185373Sjlemon		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
24285373Sjlemon		STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
24327982Sjulian		return;
24485373Sjlemon	}
24585373Sjlemon}
24627982Sjulian
24785373Sjlemonvoid
24885373Sjlemoncndebug(char *str)
24985373Sjlemon{
25085373Sjlemon	int i, len;
25185373Sjlemon
25285373Sjlemon	len = strlen(str);
25385373Sjlemon	cnputc('>'); cnputc('>'); cnputc('>'); cnputc(' ');
25485373Sjlemon	for (i = 0; i < len; i++)
25585373Sjlemon		cnputc(str[i]);
25685373Sjlemon	cnputc('\n');
25785373Sjlemon}
25885373Sjlemon
25985373Sjlemonstatic int
26085373Sjlemonsysctl_kern_console(SYSCTL_HANDLER_ARGS)
26185373Sjlemon{
26285373Sjlemon	struct cn_device *cnd;
26385373Sjlemon	struct consdev *cp, **list;
26485373Sjlemon	char *name, *p;
26585373Sjlemon	int delete, len, error;
26685373Sjlemon
26785373Sjlemon	len = 2;
26885373Sjlemon	SET_FOREACH(list, cons_set) {
26985373Sjlemon		cp = *list;
27085373Sjlemon		if (cp->cn_dev != NULL)
27185373Sjlemon			len += strlen(devtoname(cp->cn_dev)) + 1;
27256582Sbde	}
27385373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
27485373Sjlemon		len += strlen(devtoname(cnd->cnd_cn->cn_dev)) + 1;
27585373Sjlemon	len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX;
276111119Simp	MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO);
27785373Sjlemon	p = name;
27885373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
27985373Sjlemon		p += sprintf(p, "%s,", devtoname(cnd->cnd_cn->cn_dev));
28085373Sjlemon	*p++ = '/';
28185373Sjlemon	SET_FOREACH(list, cons_set) {
28285373Sjlemon		cp = *list;
28385373Sjlemon		if (cp->cn_dev != NULL)
28485373Sjlemon			p += sprintf(p, "%s,", devtoname(cp->cn_dev));
28585373Sjlemon	}
28685373Sjlemon	error = sysctl_handle_string(oidp, name, len, req);
28785373Sjlemon	if (error == 0 && req->newptr != NULL) {
28885373Sjlemon		p = name;
28985373Sjlemon		error = ENXIO;
29085373Sjlemon		delete = 0;
29185373Sjlemon		if (*p == '-') {
29285373Sjlemon			delete = 1;
29385373Sjlemon			p++;
29485373Sjlemon		}
29585373Sjlemon		SET_FOREACH(list, cons_set) {
29685373Sjlemon			cp = *list;
29785373Sjlemon			if (cp->cn_dev == NULL ||
29885373Sjlemon			    strcmp(p, devtoname(cp->cn_dev)) != 0)
29985373Sjlemon				continue;
30085373Sjlemon			if (delete) {
30185373Sjlemon				cnremove(cp);
30285373Sjlemon				error = 0;
30385373Sjlemon			} else {
30485373Sjlemon				error = cnadd(cp);
30585373Sjlemon				if (error == 0)
30685373Sjlemon					cnselect(cp);
30785373Sjlemon			}
30885373Sjlemon			break;
30985373Sjlemon		}
31085373Sjlemon	}
31185373Sjlemon	FREE(name, M_TEMP);
31285373Sjlemon	return (error);
31327982Sjulian}
31427982Sjulian
31585373SjlemonSYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW,
31685373Sjlemon	0, 0, sysctl_kern_console, "A", "Console device control");
31785373Sjlemon
31827982Sjulian/*
31927982Sjulian * User has changed the state of the console muting.
32027982Sjulian * This may require us to open or close the device in question.
32127982Sjulian */
32212675Sjulianstatic int
32362573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
32427982Sjulian{
32527982Sjulian	int error;
32627982Sjulian	int ocn_mute;
32727982Sjulian
32827982Sjulian	ocn_mute = cn_mute;
32927982Sjulian	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
33085373Sjlemon	if (error != 0 || req->newptr == NULL)
33185373Sjlemon		return (error);
33285373Sjlemon	if (ocn_mute && !cn_mute && cn_is_open)
33385373Sjlemon		error = cnopen(NODEV, openflag, 0, curthread);
33485373Sjlemon	else if (!ocn_mute && cn_mute && cn_is_open) {
33585373Sjlemon		error = cnclose(NODEV, openflag, 0, curthread);
33685373Sjlemon		cn_is_open = 1;		/* XXX hack */
33727982Sjulian	}
33827982Sjulian	return (error);
33927982Sjulian}
34027982Sjulian
34127982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
34285373Sjlemon	0, sizeof(cn_mute), sysctl_kern_consmute, "I", "");
34327982Sjulian
34427982Sjulianstatic int
34585373Sjlemoncn_devopen(struct cn_device *cnd, struct thread *td, int forceopen)
34685373Sjlemon{
34785373Sjlemon	char path[CNDEVPATHMAX];
34885884Sjlemon	struct nameidata nd;
34985884Sjlemon	struct vnode *vp;
3504Srgrimes	dev_t dev;
35185373Sjlemon	int error;
3521007Sdg
35385884Sjlemon	if ((vp = cnd->cnd_vp) != NULL) {
35485884Sjlemon		if (!forceopen && vp->v_type != VBAD) {
35585884Sjlemon			dev = vp->v_rdev;
35685373Sjlemon			return ((*devsw(dev)->d_open)(dev, openflag, 0, td));
35727982Sjulian		}
35885373Sjlemon		cnd->cnd_vp = NULL;
35991406Sjhb		vn_close(vp, openflag, td->td_ucred, td);
3605764Sbde	}
361105354Srobert	if (cnd->cnd_name[0] == '\0') {
362105354Srobert		strlcpy(cnd->cnd_name, devtoname(cnd->cnd_cn->cn_dev),
36385373Sjlemon		    sizeof(cnd->cnd_name));
364105354Srobert	}
36585373Sjlemon	snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_name);
36685373Sjlemon	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
36785373Sjlemon	error = vn_open(&nd, &openflag, 0);
36885373Sjlemon	if (error == 0) {
36985373Sjlemon		NDFREE(&nd, NDF_ONLY_PNBUF);
37085373Sjlemon		VOP_UNLOCK(nd.ni_vp, 0, td);
37185373Sjlemon		if (nd.ni_vp->v_type == VCHR)
37285373Sjlemon			cnd->cnd_vp = nd.ni_vp;
37385373Sjlemon		else
37491406Sjhb			vn_close(nd.ni_vp, openflag, td->td_ucred, td);
37585373Sjlemon	}
37685373Sjlemon	return (cnd->cnd_vp != NULL);
3774Srgrimes}
3788876Srgrimes
37912675Sjulianstatic int
38085373Sjlemoncnopen(dev_t dev, int flag, int mode, struct thread *td)
3814Srgrimes{
38285373Sjlemon	struct cn_device *cnd;
3831007Sdg
38485448Sjlemon	openflag = flag | FWRITE;	/* XXX */
38585373Sjlemon	cn_is_open = 1;			/* console is logically open */
38685373Sjlemon	if (cn_mute)
3874Srgrimes		return (0);
38885373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
38985373Sjlemon		cn_devopen(cnd, td, 0);
39085373Sjlemon	return (0);
39185373Sjlemon}
39285373Sjlemon
39385373Sjlemonstatic int
39485373Sjlemoncnclose(dev_t dev, int flag, int mode, struct thread *td)
39585373Sjlemon{
39685373Sjlemon	struct cn_device *cnd;
39785458Sjlemon	struct vnode *vp;
39885373Sjlemon
39985373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
40085458Sjlemon		if ((vp = cnd->cnd_vp) == NULL)
40185373Sjlemon			continue;
40285373Sjlemon		cnd->cnd_vp = NULL;
40391406Sjhb		vn_close(vp, openflag, td->td_ucred, td);
4045764Sbde	}
40585373Sjlemon	cn_is_open = 0;
40627982Sjulian	return (0);
4074Srgrimes}
4088876Srgrimes
40912675Sjulianstatic int
41085373Sjlemoncnread(dev_t dev, struct uio *uio, int flag)
4114Srgrimes{
41285373Sjlemon	struct cn_device *cnd;
41356582Sbde
41485373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
41585373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
4164Srgrimes		return (0);
41785373Sjlemon	dev = cnd->cnd_vp->v_rdev;
41846676Sphk	return ((*devsw(dev)->d_read)(dev, uio, flag));
4194Srgrimes}
4208876Srgrimes
42112675Sjulianstatic int
42285373Sjlemoncnwrite(dev_t dev, struct uio *uio, int flag)
4234Srgrimes{
42485373Sjlemon	struct cn_device *cnd;
42556582Sbde
42685373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
42785373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
42885373Sjlemon		goto done;
4291021Sdg	if (constty)
4304Srgrimes		dev = constty->t_dev;
4314Srgrimes	else
43285373Sjlemon		dev = cnd->cnd_vp->v_rdev;
43385373Sjlemon	if (dev != NULL) {
43485373Sjlemon		log_console(uio);
43585373Sjlemon		return ((*devsw(dev)->d_write)(dev, uio, flag));
43685373Sjlemon	}
43785373Sjlemondone:
43885373Sjlemon	uio->uio_resid = 0; /* dump the data */
43985373Sjlemon	return (0);
4404Srgrimes}
4418876Srgrimes
44212675Sjulianstatic int
44385373Sjlemoncnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
4444Srgrimes{
44585373Sjlemon	struct cn_device *cnd;
4464Srgrimes	int error;
4474Srgrimes
44885373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
44985373Sjlemon	if (cn_mute || CND_INVALID(cnd, td))
4504Srgrimes		return (0);
4514Srgrimes	/*
4524Srgrimes	 * Superuser can always use this to wrest control of console
4534Srgrimes	 * output from the "virtual" console.
4544Srgrimes	 */
4554Srgrimes	if (cmd == TIOCCONS && constty) {
45693593Sjhb		error = suser(td);
4574Srgrimes		if (error)
4584Srgrimes			return (error);
4594Srgrimes		constty = NULL;
4604Srgrimes		return (0);
4614Srgrimes	}
46285373Sjlemon	dev = cnd->cnd_vp->v_rdev;
46385373Sjlemon	if (dev != NULL)
46485373Sjlemon		return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
46585373Sjlemon	return (0);
4664Srgrimes}
4674Srgrimes
46885373Sjlemon/*
46985373Sjlemon * XXX
47085373Sjlemon * poll/kqfilter do not appear to be correct
47185373Sjlemon */
47212675Sjulianstatic int
47385373Sjlemoncnpoll(dev_t dev, int events, struct thread *td)
4744Srgrimes{
47585373Sjlemon	struct cn_device *cnd;
4766712Spst
47785373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
47885373Sjlemon	if (cn_mute || CND_INVALID(cnd, td))
47985373Sjlemon		return (0);
48085373Sjlemon	dev = cnd->cnd_vp->v_rdev;
48185373Sjlemon	if (dev != NULL)
48285373Sjlemon		return ((*devsw(dev)->d_poll)(dev, events, td));
48385373Sjlemon	return (0);
4844Srgrimes}
4854Srgrimes
48672521Sjlemonstatic int
48785373Sjlemoncnkqfilter(dev_t dev, struct knote *kn)
48872521Sjlemon{
48985373Sjlemon	struct cn_device *cnd;
49085373Sjlemon
49185373Sjlemon	cnd = STAILQ_FIRST(&cn_devlist);
49285373Sjlemon	if (cn_mute || CND_INVALID(cnd, curthread))
49372521Sjlemon		return (1);
49485373Sjlemon	dev = cnd->cnd_vp->v_rdev;
49585373Sjlemon	if (dev != NULL)
49672521Sjlemon		return ((*devsw(dev)->d_kqfilter)(dev, kn));
49772521Sjlemon	return (1);
49872521Sjlemon}
49972521Sjlemon
50085373Sjlemon/*
50185373Sjlemon * Low level console routines.
50285373Sjlemon */
503798Swollmanint
50485373Sjlemoncngetc(void)
5054Srgrimes{
5065160Sjoerg	int c;
50785373Sjlemon
50885373Sjlemon	if (cn_mute)
50919268Sjulian		return (-1);
51085373Sjlemon	while ((c = cncheckc()) == -1)
51185373Sjlemon		;
51285373Sjlemon	if (c == '\r')
51385373Sjlemon		c = '\n';		/* console input is always ICRNL */
5145160Sjoerg	return (c);
5154Srgrimes}
5164Srgrimes
5173728Sphkint
51885373Sjlemoncncheckc(void)
5193728Sphk{
52085373Sjlemon	struct cn_device *cnd;
52185373Sjlemon	struct consdev *cn;
52285373Sjlemon	int c;
52385373Sjlemon
52485373Sjlemon	if (cn_mute)
52518287Sbde		return (-1);
52685373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
52785373Sjlemon		cn = cnd->cnd_cn;
528111194Sphk		c = cn->cn_checkc(cn);
52985373Sjlemon		if (c != -1) {
53085373Sjlemon			return (c);
53185373Sjlemon		}
53285373Sjlemon	}
53385373Sjlemon	return (-1);
5343728Sphk}
5353728Sphk
536798Swollmanvoid
53785373Sjlemoncnputc(int c)
5384Srgrimes{
53985373Sjlemon	struct cn_device *cnd;
54085373Sjlemon	struct consdev *cn;
54187620Sguido	char *cp;
54285373Sjlemon
54385373Sjlemon	if (cn_mute || c == '\0')
5444Srgrimes		return;
54585373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
54685373Sjlemon		cn = cnd->cnd_cn;
5474Srgrimes		if (c == '\n')
548111194Sphk			cn->cn_putc(cn, '\r');
549111194Sphk		cn->cn_putc(cn, c);
5504Srgrimes	}
55187649Sguido#ifdef DDB
55287620Sguido	if (console_pausing && !db_active && (c == '\n')) {
55387649Sguido#else
55487649Sguido	if (console_pausing && (c == '\n')) {
55587649Sguido#endif
55687620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
55787620Sguido			cnputc(*cp);
55887620Sguido		if (cngetc() == '.')
55987620Sguido			console_pausing = 0;
56087620Sguido		cnputc('\r');
56187620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
56287620Sguido			cnputc(' ');
56387620Sguido		cnputc('\r');
56487620Sguido	}
5654Srgrimes}
5664Srgrimes
56755823Syokotavoid
56885373Sjlemoncndbctl(int on)
56955823Syokota{
57085373Sjlemon	struct cn_device *cnd;
57185373Sjlemon	struct consdev *cn;
57255823Syokota	static int refcount;
57355823Syokota
57455823Syokota	if (!on)
57555823Syokota		refcount--;
57685373Sjlemon	if (refcount == 0)
57785373Sjlemon		STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
57885373Sjlemon			cn = cnd->cnd_cn;
57985373Sjlemon			if (cn->cn_dbctl != NULL)
580111194Sphk				cn->cn_dbctl(cn, on);
58185373Sjlemon		}
58255823Syokota	if (on)
58355823Syokota		refcount++;
58455823Syokota}
58555823Syokota
58612675Sjulianstatic void
58712675Sjuliancn_drvinit(void *unused)
58812517Sjulian{
58912517Sjulian
590107984Sphk	make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
59156525Sbde	    "console");
59212517Sjulian}
59312517Sjulian
59412517SjulianSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
595