1139804Simp/*-
24Srgrimes * Copyright (c) 1988 University of Utah.
34Srgrimes * Copyright (c) 1991 The Regents of the University of California.
4235407Savg * Copyright (c) 1999 Michael Smith
5235407Savg * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6235407Savg *
74Srgrimes * All rights reserved.
84Srgrimes *
94Srgrimes * This code is derived from software contributed to Berkeley by
104Srgrimes * the Systems Programming Group of the University of Utah Computer
114Srgrimes * Science Department.
124Srgrimes *
134Srgrimes * Redistribution and use in source and binary forms, with or without
144Srgrimes * modification, are permitted provided that the following conditions
154Srgrimes * are met:
164Srgrimes * 1. Redistributions of source code must retain the above copyright
174Srgrimes *    notice, this list of conditions and the following disclaimer.
184Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
194Srgrimes *    notice, this list of conditions and the following disclaimer in the
204Srgrimes *    documentation and/or other materials provided with the distribution.
214Srgrimes * 4. Neither the name of the University nor the names of its contributors
224Srgrimes *    may be used to endorse or promote products derived from this software
234Srgrimes *    without specific prior written permission.
244Srgrimes *
254Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
264Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
274Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
284Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
294Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
304Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
314Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
324Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
334Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
344Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
354Srgrimes * SUCH DAMAGE.
364Srgrimes *
37620Srgrimes *	from: @(#)cons.c	7.2 (Berkeley) 5/9/91
384Srgrimes */
394Srgrimes
40116182Sobrien#include <sys/cdefs.h>
41116182Sobrien__FBSDID("$FreeBSD$");
42116182Sobrien
4387649Sguido#include "opt_ddb.h"
4487649Sguido
452056Swollman#include <sys/param.h>
461549Srgrimes#include <sys/systm.h>
47163858Sjb#include <sys/lock.h>
48163858Sjb#include <sys/mutex.h>
495764Sbde#include <sys/conf.h>
5056525Sbde#include <sys/cons.h>
5185448Sjlemon#include <sys/fcntl.h>
52131931Smarcel#include <sys/kdb.h>
5312675Sjulian#include <sys/kernel.h>
5485373Sjlemon#include <sys/malloc.h>
55116663Siedowse#include <sys/msgbuf.h>
5685373Sjlemon#include <sys/namei.h>
57164033Srwatson#include <sys/priv.h>
5869929Sobrien#include <sys/proc.h>
5985373Sjlemon#include <sys/queue.h>
6018951Sjulian#include <sys/reboot.h>
6112701Sphk#include <sys/sysctl.h>
62174905Swkoszek#include <sys/sbuf.h>
632056Swollman#include <sys/tty.h>
6434924Sbde#include <sys/uio.h>
6585373Sjlemon#include <sys/vnode.h>
664Srgrimes
6787620Sguido#include <ddb/ddb.h>
6887620Sguido
6912701Sphk#include <machine/cpu.h>
70177642Sphk#include <machine/clock.h>
714Srgrimes
72179246Sedstatic MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
73179246Sed
7485373Sjlemonstruct cn_device {
7585373Sjlemon	STAILQ_ENTRY(cn_device) cnd_next;
7685373Sjlemon	struct		consdev *cnd_cn;
7785373Sjlemon};
7885373Sjlemon
7985373Sjlemon#define CNDEVPATHMAX	32
8085373Sjlemon#define CNDEVTAB_SIZE	4
8185373Sjlemonstatic struct cn_device cn_devtab[CNDEVTAB_SIZE];
8285373Sjlemonstatic STAILQ_HEAD(, cn_device) cn_devlist =
8385373Sjlemon    STAILQ_HEAD_INITIALIZER(cn_devlist);
8485373Sjlemon
85125467Skanint	cons_avail_mask = 0;	/* Bit mask. Each registered low level console
86125467Skan				 * which is currently unavailable for inpit
87125467Skan				 * (i.e., if it is in graphics mode) will have
88125467Skan				 * this bit cleared.
897680Sjoerg				 */
9085373Sjlemonstatic int cn_mute;
91116663Siedowsestatic char *consbuf;			/* buffer used by `consmsgbuf' */
92116663Siedowsestatic struct callout conscallout;	/* callout for outputting to constty */
93116663Siedowsestruct msgbuf consmsgbuf;		/* message buffer for console tty */
9487620Sguidostatic u_char console_pausing;		/* pause after each line during probe */
9587620Sguidostatic char *console_pausestr=
9687620Sguido"<pause; press any key to proceed to next line or '.' to end pause mode>";
97116663Siedowsestruct tty *constty;			/* pointer to console "window" tty */
98163858Sjbstatic struct mtx cnputs_mtx;		/* Mutex for cnputs(). */
99163858Sjbstatic int use_cnputs_mtx = 0;		/* != 0 if cnputs_mtx locking reqd. */
1005764Sbde
101116663Siedowsestatic void constty_timeout(void *arg);
10285448Sjlemon
103158944Sphkstatic struct consdev cons_consdev;
104158944SphkDATA_SET(cons_set, cons_consdev);
10578161SpeterSET_DECLARE(cons_set, struct consdev);
10642373Syokota
107798Swollmanvoid
10885373Sjlemoncninit(void)
1094Srgrimes{
11085373Sjlemon	struct consdev *best_cn, *cn, **list;
1114Srgrimes
1124Srgrimes	/*
11318951Sjulian	 * Check if we should mute the console (for security reasons perhaps)
11418951Sjulian	 * It can be changes dynamically using sysctl kern.consmute
11518951Sjulian	 * once we are up and going.
11618951Sjulian	 *
11718951Sjulian	 */
11818951Sjulian        cn_mute = ((boothowto & (RB_MUTE
11918951Sjulian			|RB_SINGLE
12018951Sjulian			|RB_VERBOSE
121138249Sscottl			|RB_ASKNAME)) == RB_MUTE);
12285373Sjlemon
12318951Sjulian	/*
12485373Sjlemon	 * Find the first console with the highest priority.
1254Srgrimes	 */
12685373Sjlemon	best_cn = NULL;
12785373Sjlemon	SET_FOREACH(list, cons_set) {
12885373Sjlemon		cn = *list;
129101436Sjake		cnremove(cn);
130196506Sed		/* Skip cons_consdev. */
131196506Sed		if (cn->cn_ops == NULL)
13285373Sjlemon			continue;
133196506Sed		cn->cn_ops->cn_probe(cn);
13485373Sjlemon		if (cn->cn_pri == CN_DEAD)
13585373Sjlemon			continue;
13685373Sjlemon		if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
13785373Sjlemon			best_cn = cn;
13885373Sjlemon		if (boothowto & RB_MULTIPLE) {
13985373Sjlemon			/*
14085373Sjlemon			 * Initialize console, and attach to it.
14185373Sjlemon			 */
142196506Sed			cn->cn_ops->cn_init(cn);
14385373Sjlemon			cnadd(cn);
14485373Sjlemon		}
14585373Sjlemon	}
14685373Sjlemon	if (best_cn == NULL)
1474Srgrimes		return;
14885373Sjlemon	if ((boothowto & RB_MULTIPLE) == 0) {
149196506Sed		best_cn->cn_ops->cn_init(best_cn);
15085373Sjlemon		cnadd(best_cn);
15110665Sbde	}
15287620Sguido	if (boothowto & RB_PAUSE)
15387620Sguido		console_pausing = 1;
1544Srgrimes	/*
15585373Sjlemon	 * Make the best console the preferred console.
15610665Sbde	 */
15785373Sjlemon	cnselect(best_cn);
15885373Sjlemon}
15985373Sjlemon
16087620Sguidovoid
16187620Sguidocninit_finish()
16287620Sguido{
16387620Sguido	console_pausing = 0;
16487620Sguido}
16587620Sguido
16685373Sjlemon/* add a new physical console to back the virtual console */
16785373Sjlemonint
16885373Sjlemoncnadd(struct consdev *cn)
16985373Sjlemon{
17085373Sjlemon	struct cn_device *cnd;
17185373Sjlemon	int i;
17285373Sjlemon
17385373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
17485373Sjlemon		if (cnd->cnd_cn == cn)
17585373Sjlemon			return (0);
17685373Sjlemon	for (i = 0; i < CNDEVTAB_SIZE; i++) {
17785373Sjlemon		cnd = &cn_devtab[i];
17885373Sjlemon		if (cnd->cnd_cn == NULL)
17985373Sjlemon			break;
18048104Syokota	}
18185373Sjlemon	if (cnd->cnd_cn != NULL)
18285373Sjlemon		return (ENOMEM);
18385373Sjlemon	cnd->cnd_cn = cn;
184120456Sphk	if (cn->cn_name[0] == '\0') {
185120456Sphk		/* XXX: it is unclear if/where this print might output */
186120456Sphk		printf("WARNING: console at %p has no name\n", cn);
187120456Sphk	}
18885373Sjlemon	STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
189184521Sed	if (STAILQ_FIRST(&cn_devlist) == cnd)
190184521Sed		ttyconsdev_select(cnd->cnd_cn->cn_name);
191125467Skan
192125467Skan	/* Add device to the active mask. */
193125467Skan	cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0);
194125467Skan
19585373Sjlemon	return (0);
19610665Sbde}
19710665Sbde
19810665Sbdevoid
19985373Sjlemoncnremove(struct consdev *cn)
20010665Sbde{
20185373Sjlemon	struct cn_device *cnd;
202125467Skan	int i;
20310665Sbde
20485373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
20585373Sjlemon		if (cnd->cnd_cn != cn)
20685373Sjlemon			continue;
207184521Sed		if (STAILQ_FIRST(&cn_devlist) == cnd)
208184521Sed			ttyconsdev_select(NULL);
20985373Sjlemon		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
21085373Sjlemon		cnd->cnd_cn = NULL;
211125467Skan
212125467Skan		/* Remove this device from available mask. */
213125467Skan		for (i = 0; i < CNDEVTAB_SIZE; i++)
214125467Skan			if (cnd == &cn_devtab[i]) {
215125467Skan				cons_avail_mask &= ~(1 << i);
216125467Skan				break;
217125467Skan			}
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)
225196506Sed			cn->cn_ops->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);
243184521Sed		ttyconsdev_select(cnd->cnd_cn->cn_name);
24427982Sjulian		return;
24585373Sjlemon	}
24685373Sjlemon}
24727982Sjulian
24885373Sjlemonvoid
249125467Skancnavailable(struct consdev *cn, int available)
250125467Skan{
251125467Skan	int i;
252125467Skan
253125467Skan	for (i = 0; i < CNDEVTAB_SIZE; i++) {
254125467Skan		if (cn_devtab[i].cnd_cn == cn)
255125467Skan			break;
256125467Skan	}
257125467Skan	if (available) {
258125467Skan		if (i < CNDEVTAB_SIZE)
259125467Skan			cons_avail_mask |= (1 << i);
260125467Skan		cn->cn_flags &= ~CN_FLAG_NOAVAIL;
261125467Skan	} else {
262125467Skan		if (i < CNDEVTAB_SIZE)
263125467Skan			cons_avail_mask &= ~(1 << i);
264125467Skan		cn->cn_flags |= CN_FLAG_NOAVAIL;
265125467Skan	}
266125467Skan}
267125467Skan
268125467Skanint
269125487Skancnunavailable(void)
270125467Skan{
271125487Skan
272125467Skan	return (cons_avail_mask == 0);
273125467Skan}
274125467Skan
275120456Sphk/*
276174905Swkoszek * sysctl_kern_console() provides output parseable in conscontrol(1).
277120456Sphk */
27885373Sjlemonstatic int
27985373Sjlemonsysctl_kern_console(SYSCTL_HANDLER_ARGS)
28085373Sjlemon{
28185373Sjlemon	struct cn_device *cnd;
28285373Sjlemon	struct consdev *cp, **list;
283174905Swkoszek	char *p;
284174905Swkoszek	int delete, error;
285174905Swkoszek	struct sbuf *sb;
28685373Sjlemon
287174905Swkoszek	sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND);
288174905Swkoszek	if (sb == NULL)
289174905Swkoszek		return (ENOMEM);
290174905Swkoszek	sbuf_clear(sb);
29185373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
292174905Swkoszek		sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name);
293174905Swkoszek	sbuf_printf(sb, "/");
29485373Sjlemon	SET_FOREACH(list, cons_set) {
29585373Sjlemon		cp = *list;
296120456Sphk		if (cp->cn_name[0] != '\0')
297174905Swkoszek			sbuf_printf(sb, "%s,", cp->cn_name);
29885373Sjlemon	}
299174905Swkoszek	sbuf_finish(sb);
300174905Swkoszek	error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req);
30185373Sjlemon	if (error == 0 && req->newptr != NULL) {
302174905Swkoszek		p = sbuf_data(sb);
30385373Sjlemon		error = ENXIO;
30485373Sjlemon		delete = 0;
30585373Sjlemon		if (*p == '-') {
30685373Sjlemon			delete = 1;
30785373Sjlemon			p++;
30885373Sjlemon		}
30985373Sjlemon		SET_FOREACH(list, cons_set) {
31085373Sjlemon			cp = *list;
311120456Sphk			if (strcmp(p, cp->cn_name) != 0)
31285373Sjlemon				continue;
31385373Sjlemon			if (delete) {
31485373Sjlemon				cnremove(cp);
31585373Sjlemon				error = 0;
31685373Sjlemon			} else {
31785373Sjlemon				error = cnadd(cp);
31885373Sjlemon				if (error == 0)
31985373Sjlemon					cnselect(cp);
32085373Sjlemon			}
32185373Sjlemon			break;
32285373Sjlemon		}
32385373Sjlemon	}
324174905Swkoszek	sbuf_delete(sb);
32585373Sjlemon	return (error);
32627982Sjulian}
32727982Sjulian
32885373SjlemonSYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW,
32985373Sjlemon	0, 0, sysctl_kern_console, "A", "Console device control");
33085373Sjlemon
33127982Sjulian/*
33227982Sjulian * User has changed the state of the console muting.
33327982Sjulian * This may require us to open or close the device in question.
33427982Sjulian */
33512675Sjulianstatic int
33662573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
33727982Sjulian{
33827982Sjulian	int error;
33927982Sjulian
34027982Sjulian	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
34185373Sjlemon	if (error != 0 || req->newptr == NULL)
34285373Sjlemon		return (error);
34327982Sjulian	return (error);
34427982Sjulian}
34527982Sjulian
34627982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
347211102Sgavin	0, sizeof(cn_mute), sysctl_kern_consmute, "I",
348211102Sgavin	"State of the console muting");
34927982Sjulian
350235405Savgvoid
351235405Savgcngrab()
352235405Savg{
353235405Savg	struct cn_device *cnd;
354235405Savg	struct consdev *cn;
355235405Savg
356235405Savg	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
357235405Savg		cn = cnd->cnd_cn;
358235405Savg		if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
359235405Savg			cn->cn_ops->cn_grab(cn);
360235405Savg	}
361235405Savg}
362235405Savg
363235405Savgvoid
364235405Savgcnungrab()
365235405Savg{
366235405Savg	struct cn_device *cnd;
367235405Savg	struct consdev *cn;
368235405Savg
369235405Savg	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
370235405Savg		cn = cnd->cnd_cn;
371235405Savg		if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
372235405Savg			cn->cn_ops->cn_ungrab(cn);
373235405Savg	}
374235405Savg}
375235405Savg
37685373Sjlemon/*
37785373Sjlemon * Low level console routines.
37885373Sjlemon */
379798Swollmanint
38085373Sjlemoncngetc(void)
3814Srgrimes{
3825160Sjoerg	int c;
38385373Sjlemon
38485373Sjlemon	if (cn_mute)
38519268Sjulian		return (-1);
38685373Sjlemon	while ((c = cncheckc()) == -1)
387241637Savg		cpu_spinwait();
38885373Sjlemon	if (c == '\r')
38985373Sjlemon		c = '\n';		/* console input is always ICRNL */
3905160Sjoerg	return (c);
3914Srgrimes}
3924Srgrimes
3933728Sphkint
39485373Sjlemoncncheckc(void)
3953728Sphk{
39685373Sjlemon	struct cn_device *cnd;
39785373Sjlemon	struct consdev *cn;
39885373Sjlemon	int c;
39985373Sjlemon
40085373Sjlemon	if (cn_mute)
40118287Sbde		return (-1);
40285373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
40385373Sjlemon		cn = cnd->cnd_cn;
404131931Smarcel		if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
405196506Sed			c = cn->cn_ops->cn_getc(cn);
406196506Sed			if (c != -1)
407121182Srwatson				return (c);
40885373Sjlemon		}
40985373Sjlemon	}
41085373Sjlemon	return (-1);
4113728Sphk}
4123728Sphk
413798Swollmanvoid
414235407Savgcngets(char *cp, size_t size, int visible)
415235407Savg{
416235407Savg	char *lp, *end;
417235407Savg	int c;
418235407Savg
419235407Savg	cngrab();
420235407Savg
421235407Savg	lp = cp;
422235407Savg	end = cp + size - 1;
423235407Savg	for (;;) {
424235407Savg		c = cngetc() & 0177;
425235407Savg		switch (c) {
426235407Savg		case '\n':
427235407Savg		case '\r':
428235407Savg			cnputc(c);
429235407Savg			*lp = '\0';
430235407Savg			cnungrab();
431235407Savg			return;
432235407Savg		case '\b':
433235407Savg		case '\177':
434235407Savg			if (lp > cp) {
435235407Savg				if (visible) {
436235407Savg					cnputc(c);
437235407Savg					cnputs(" \b");
438235407Savg				}
439235407Savg				lp--;
440235407Savg			}
441235407Savg			continue;
442235407Savg		case '\0':
443235407Savg			continue;
444235407Savg		default:
445235407Savg			if (lp < end) {
446235407Savg				switch (visible) {
447235407Savg				case GETS_NOECHO:
448235407Savg					break;
449235407Savg				case GETS_ECHOPASS:
450235407Savg					cnputc('*');
451235407Savg					break;
452235407Savg				default:
453235407Savg					cnputc(c);
454235407Savg					break;
455235407Savg				}
456235407Savg				*lp++ = c;
457235407Savg			}
458235407Savg		}
459235407Savg	}
460235407Savg}
461235407Savg
462235407Savgvoid
46385373Sjlemoncnputc(int c)
4644Srgrimes{
46585373Sjlemon	struct cn_device *cnd;
46685373Sjlemon	struct consdev *cn;
46787620Sguido	char *cp;
46885373Sjlemon
46985373Sjlemon	if (cn_mute || c == '\0')
4704Srgrimes		return;
47185373Sjlemon	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
47285373Sjlemon		cn = cnd->cnd_cn;
473131931Smarcel		if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
474121182Srwatson			if (c == '\n')
475196506Sed				cn->cn_ops->cn_putc(cn, '\r');
476196506Sed			cn->cn_ops->cn_putc(cn, c);
477121182Srwatson		}
4784Srgrimes	}
479131931Smarcel	if (console_pausing && c == '\n' && !kdb_active) {
48087620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
48187620Sguido			cnputc(*cp);
482235406Savg		cngrab();
48387620Sguido		if (cngetc() == '.')
48487620Sguido			console_pausing = 0;
485235406Savg		cnungrab();
48687620Sguido		cnputc('\r');
48787620Sguido		for (cp = console_pausestr; *cp != '\0'; cp++)
48887620Sguido			cnputc(' ');
48987620Sguido		cnputc('\r');
49087620Sguido	}
4914Srgrimes}
4924Srgrimes
493163858Sjbvoid
494163858Sjbcnputs(char *p)
495163858Sjb{
496163858Sjb	int c;
497163858Sjb	int unlock_reqd = 0;
498163858Sjb
499163858Sjb	if (use_cnputs_mtx) {
500163858Sjb		mtx_lock_spin(&cnputs_mtx);
501163858Sjb		unlock_reqd = 1;
502163858Sjb	}
503163858Sjb
504163858Sjb	while ((c = *p++) != '\0')
505163858Sjb		cnputc(c);
506163858Sjb
507163858Sjb	if (unlock_reqd)
508163858Sjb		mtx_unlock_spin(&cnputs_mtx);
509163858Sjb}
510163858Sjb
511116663Siedowsestatic int consmsgbuf_size = 8192;
512116663SiedowseSYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0,
513211102Sgavin    "Console tty buffer size");
514116663Siedowse
515116663Siedowse/*
516116663Siedowse * Redirect console output to a tty.
517116663Siedowse */
518116663Siedowsevoid
519116663Siedowseconstty_set(struct tty *tp)
520116663Siedowse{
521116663Siedowse	int size;
522116663Siedowse
523116663Siedowse	KASSERT(tp != NULL, ("constty_set: NULL tp"));
524116663Siedowse	if (consbuf == NULL) {
525116663Siedowse		size = consmsgbuf_size;
526179246Sed		consbuf = malloc(size, M_TTYCONS, M_WAITOK);
527116663Siedowse		msgbuf_init(&consmsgbuf, consbuf, size);
528116663Siedowse		callout_init(&conscallout, 0);
529116663Siedowse	}
530116663Siedowse	constty = tp;
531116663Siedowse	constty_timeout(NULL);
532116663Siedowse}
533116663Siedowse
534116663Siedowse/*
535116663Siedowse * Disable console redirection to a tty.
536116663Siedowse */
537116663Siedowsevoid
538116663Siedowseconstty_clear(void)
539116663Siedowse{
540116663Siedowse	int c;
541116663Siedowse
542116663Siedowse	constty = NULL;
543116663Siedowse	if (consbuf == NULL)
544116663Siedowse		return;
545116663Siedowse	callout_stop(&conscallout);
546116663Siedowse	while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
547116663Siedowse		cnputc(c);
548179246Sed	free(consbuf, M_TTYCONS);
549116663Siedowse	consbuf = NULL;
550116663Siedowse}
551116663Siedowse
552116663Siedowse/* Times per second to check for pending console tty messages. */
553116663Siedowsestatic int constty_wakeups_per_second = 5;
554116663SiedowseSYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
555211102Sgavin    &constty_wakeups_per_second, 0,
556211102Sgavin    "Times per second to check for pending console tty messages");
557116663Siedowse
558112046Sphkstatic void
559116663Siedowseconstty_timeout(void *arg)
560116663Siedowse{
561116663Siedowse	int c;
562116663Siedowse
563181905Sed	if (constty != NULL) {
564181905Sed		tty_lock(constty);
565181905Sed		while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
566181905Sed			if (tty_putchar(constty, c) < 0) {
567181905Sed				tty_unlock(constty);
568181905Sed				constty = NULL;
569181905Sed				break;
570181905Sed			}
571181905Sed		}
572181905Sed
573181905Sed		if (constty != NULL)
574181905Sed			tty_unlock(constty);
575116663Siedowse	}
576116663Siedowse	if (constty != NULL) {
577116663Siedowse		callout_reset(&conscallout, hz / constty_wakeups_per_second,
578116663Siedowse		    constty_timeout, NULL);
579116663Siedowse	} else {
580116663Siedowse		/* Deallocate the constty buffer memory. */
581116663Siedowse		constty_clear();
582116663Siedowse	}
583116663Siedowse}
584116663Siedowse
585116663Siedowsestatic void
586112046Sphkcn_drvinit(void *unused)
587112046Sphk{
588112046Sphk
589163858Sjb	mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS);
590163858Sjb	use_cnputs_mtx = 1;
591112046Sphk}
592112046Sphk
593177253SrwatsonSYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL);
594177642Sphk
595177642Sphk/*
596177642Sphk * Sysbeep(), if we have hardware for it
597177642Sphk */
598177642Sphk
599177642Sphk#ifdef HAS_TIMER_SPKR
600177642Sphk
601177642Sphkstatic int beeping;
602177642Sphk
603177642Sphkstatic void
604177642Sphksysbeepstop(void *chan)
605177642Sphk{
606177642Sphk
607177642Sphk	timer_spkr_release();
608177642Sphk	beeping = 0;
609177642Sphk}
610177642Sphk
611177642Sphkint
612177642Sphksysbeep(int pitch, int period)
613177642Sphk{
614177642Sphk
615177642Sphk	if (timer_spkr_acquire()) {
616177642Sphk		if (!beeping) {
617177642Sphk			/* Something else owns it. */
618177642Sphk			return (EBUSY);
619177642Sphk		}
620177642Sphk	}
621177642Sphk	timer_spkr_setfreq(pitch);
622177642Sphk	if (!beeping) {
623177642Sphk		beeping = period;
624177642Sphk		timeout(sysbeepstop, (void *)NULL, period);
625177642Sphk	}
626177642Sphk	return (0);
627177642Sphk}
628177642Sphk
629177642Sphk#else
630177642Sphk
631177642Sphk/*
632177642Sphk * No hardware, no sound
633177642Sphk */
634177642Sphk
635177642Sphkint
636177642Sphksysbeep(int pitch __unused, int period __unused)
637177642Sphk{
638177642Sphk
639177642Sphk	return (ENODEV);
640177642Sphk}
641177642Sphk
642177642Sphk#endif
643177642Sphk
644