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