kern_cons.c revision 116663
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 394Srgrimes */ 404Srgrimes 41116182Sobrien#include <sys/cdefs.h> 42116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/tty_cons.c 116663 2003-06-22 02:54:33Z iedowse $"); 43116182Sobrien 4487649Sguido#include "opt_ddb.h" 4587649Sguido 462056Swollman#include <sys/param.h> 471549Srgrimes#include <sys/systm.h> 485764Sbde#include <sys/conf.h> 4956525Sbde#include <sys/cons.h> 5085448Sjlemon#include <sys/fcntl.h> 5112675Sjulian#include <sys/kernel.h> 5285373Sjlemon#include <sys/malloc.h> 53116663Siedowse#include <sys/msgbuf.h> 5485373Sjlemon#include <sys/namei.h> 5569929Sobrien#include <sys/proc.h> 5685373Sjlemon#include <sys/queue.h> 5718951Sjulian#include <sys/reboot.h> 5812701Sphk#include <sys/sysctl.h> 592056Swollman#include <sys/tty.h> 6034924Sbde#include <sys/uio.h> 6185373Sjlemon#include <sys/vnode.h> 624Srgrimes 6387620Sguido#include <ddb/ddb.h> 6487620Sguido 6512701Sphk#include <machine/cpu.h> 664Srgrimes 6712675Sjulianstatic d_open_t cnopen; 6812675Sjulianstatic d_close_t cnclose; 6912675Sjulianstatic d_read_t cnread; 7012675Sjulianstatic d_write_t cnwrite; 7112675Sjulianstatic d_ioctl_t cnioctl; 7229368Speterstatic d_poll_t cnpoll; 7372521Sjlemonstatic d_kqfilter_t cnkqfilter; 7412675Sjulian 7547625Sphkstatic struct cdevsw cn_cdevsw = { 76111815Sphk .d_open = cnopen, 77111815Sphk .d_close = cnclose, 78111815Sphk .d_read = cnread, 79111815Sphk .d_write = cnwrite, 80111815Sphk .d_ioctl = cnioctl, 81111815Sphk .d_poll = cnpoll, 82111815Sphk .d_name = "console", 83112035Sphk .d_maj = 256, 84112035Sphk /* 85112035Sphk * XXX: We really want major #0, but zero here means 86112035Sphk * XXX: allocate a major number automatically. 87112035Sphk * XXX: kern_conf.c knows what to do when it sees 256. 88112035Sphk */ 89111821Sphk .d_flags = D_TTY, 90111815Sphk .d_kqfilter = cnkqfilter, 9138485Sbde}; 9212675Sjulian 9385373Sjlemonstruct cn_device { 9485373Sjlemon STAILQ_ENTRY(cn_device) cnd_next; 9585373Sjlemon char cnd_name[16]; 9685373Sjlemon struct vnode *cnd_vp; 9785373Sjlemon struct consdev *cnd_cn; 9885373Sjlemon}; 9985373Sjlemon 10085373Sjlemon#define CNDEVPATHMAX 32 10185373Sjlemon#define CNDEVTAB_SIZE 4 10285373Sjlemonstatic struct cn_device cn_devtab[CNDEVTAB_SIZE]; 10385373Sjlemonstatic STAILQ_HEAD(, cn_device) cn_devlist = 10485373Sjlemon STAILQ_HEAD_INITIALIZER(cn_devlist); 10585373Sjlemon 10685373Sjlemon#define CND_INVALID(cnd, td) \ 10785373Sjlemon (cnd == NULL || cnd->cnd_vp == NULL || \ 10885373Sjlemon (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1))) 10985373Sjlemon 11049049Syokotastatic udev_t cn_udev_t; 11141612SeivindSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 11249049Syokota &cn_udev_t, sizeof cn_udev_t, "T,dev_t", ""); 11327982Sjulian 1147680Sjoergint cons_unavail = 0; /* XXX: 1157680Sjoerg * physical console not available for 1167680Sjoerg * input (i.e., it is in graphics mode) 1177680Sjoerg */ 11885373Sjlemonstatic int cn_mute; 11985373Sjlemonstatic int openflag; /* how /dev/console was opened */ 12085373Sjlemonstatic int cn_is_open; 121116663Siedowsestatic char *consbuf; /* buffer used by `consmsgbuf' */ 122116663Siedowsestatic struct callout conscallout; /* callout for outputting to constty */ 123116663Siedowsestruct msgbuf consmsgbuf; /* message buffer for console tty */ 12487620Sguidostatic u_char console_pausing; /* pause after each line during probe */ 12587620Sguidostatic char *console_pausestr= 12687620Sguido"<pause; press any key to proceed to next line or '.' to end pause mode>"; 127116663Siedowsestruct tty *constty; /* pointer to console "window" tty */ 1285764Sbde 12985448Sjlemonvoid cndebug(char *); 130116663Siedowsestatic void constty_timeout(void *arg); 13185448Sjlemon 13255823SyokotaCONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 13378161SpeterSET_DECLARE(cons_set, struct consdev); 13442373Syokota 135798Swollmanvoid 13685373Sjlemoncninit(void) 1374Srgrimes{ 13885373Sjlemon struct consdev *best_cn, *cn, **list; 1394Srgrimes 1404Srgrimes /* 14118951Sjulian * Check if we should mute the console (for security reasons perhaps) 14218951Sjulian * It can be changes dynamically using sysctl kern.consmute 14318951Sjulian * once we are up and going. 14418951Sjulian * 14518951Sjulian */ 14618951Sjulian cn_mute = ((boothowto & (RB_MUTE 14718951Sjulian |RB_SINGLE 14818951Sjulian |RB_VERBOSE 14918951Sjulian |RB_ASKNAME 15018951Sjulian |RB_CONFIG)) == RB_MUTE); 15185373Sjlemon 15218951Sjulian /* 15385373Sjlemon * Find the first console with the highest priority. 1544Srgrimes */ 15585373Sjlemon best_cn = NULL; 15685373Sjlemon SET_FOREACH(list, cons_set) { 15785373Sjlemon cn = *list; 158101436Sjake cnremove(cn); 15985373Sjlemon if (cn->cn_probe == NULL) 16085373Sjlemon continue; 16185373Sjlemon cn->cn_probe(cn); 16285373Sjlemon if (cn->cn_pri == CN_DEAD) 16385373Sjlemon continue; 16485373Sjlemon if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri) 16585373Sjlemon best_cn = cn; 16685373Sjlemon if (boothowto & RB_MULTIPLE) { 16785373Sjlemon /* 16885373Sjlemon * Initialize console, and attach to it. 16985373Sjlemon */ 17085373Sjlemon cnadd(cn); 17185373Sjlemon cn->cn_init(cn); 17285373Sjlemon } 17385373Sjlemon } 17485373Sjlemon if (best_cn == NULL) 1754Srgrimes return; 17685373Sjlemon if ((boothowto & RB_MULTIPLE) == 0) { 17785373Sjlemon cnadd(best_cn); 17885373Sjlemon best_cn->cn_init(best_cn); 17910665Sbde } 18087620Sguido if (boothowto & RB_PAUSE) 18187620Sguido console_pausing = 1; 1824Srgrimes /* 18385373Sjlemon * Make the best console the preferred console. 18410665Sbde */ 18585373Sjlemon cnselect(best_cn); 18685373Sjlemon} 18785373Sjlemon 18887620Sguidovoid 18987620Sguidocninit_finish() 19087620Sguido{ 19187620Sguido console_pausing = 0; 19287620Sguido} 19387620Sguido 19485373Sjlemon/* add a new physical console to back the virtual console */ 19585373Sjlemonint 19685373Sjlemoncnadd(struct consdev *cn) 19785373Sjlemon{ 19885373Sjlemon struct cn_device *cnd; 19985373Sjlemon int i; 20085373Sjlemon 20185373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 20285373Sjlemon if (cnd->cnd_cn == cn) 20385373Sjlemon return (0); 20485373Sjlemon for (i = 0; i < CNDEVTAB_SIZE; i++) { 20585373Sjlemon cnd = &cn_devtab[i]; 20685373Sjlemon if (cnd->cnd_cn == NULL) 20785373Sjlemon break; 20848104Syokota } 20985373Sjlemon if (cnd->cnd_cn != NULL) 21085373Sjlemon return (ENOMEM); 21185373Sjlemon cnd->cnd_cn = cn; 21285373Sjlemon STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 21385373Sjlemon return (0); 21410665Sbde} 21510665Sbde 21610665Sbdevoid 21785373Sjlemoncnremove(struct consdev *cn) 21810665Sbde{ 21985373Sjlemon struct cn_device *cnd; 22010665Sbde 22185373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 22285373Sjlemon if (cnd->cnd_cn != cn) 22385373Sjlemon continue; 22485373Sjlemon STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 22585373Sjlemon if (cnd->cnd_vp != NULL) 22685373Sjlemon vn_close(cnd->cnd_vp, openflag, NOCRED, NULL); 22785373Sjlemon cnd->cnd_vp = NULL; 22885373Sjlemon cnd->cnd_cn = NULL; 22985373Sjlemon cnd->cnd_name[0] = '\0'; 23085373Sjlemon#if 0 23185373Sjlemon /* 23285373Sjlemon * XXX 23385373Sjlemon * syscons gets really confused if console resources are 23485373Sjlemon * freed after the system has initialized. 23585373Sjlemon */ 23685373Sjlemon if (cn->cn_term != NULL) 23785373Sjlemon cn->cn_term(cn); 23885373Sjlemon#endif 23910665Sbde return; 24056582Sbde } 2414Srgrimes} 2424Srgrimes 24385373Sjlemonvoid 24485373Sjlemoncnselect(struct consdev *cn) 24527982Sjulian{ 24685373Sjlemon struct cn_device *cnd; 24727982Sjulian 24885373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 24985373Sjlemon if (cnd->cnd_cn != cn) 25085373Sjlemon continue; 25185373Sjlemon if (cnd == STAILQ_FIRST(&cn_devlist)) 25285373Sjlemon return; 25385373Sjlemon STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 25485373Sjlemon STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 25527982Sjulian return; 25685373Sjlemon } 25785373Sjlemon} 25827982Sjulian 25985373Sjlemonvoid 26085373Sjlemoncndebug(char *str) 26185373Sjlemon{ 26285373Sjlemon int i, len; 26385373Sjlemon 26485373Sjlemon len = strlen(str); 26585373Sjlemon cnputc('>'); cnputc('>'); cnputc('>'); cnputc(' '); 26685373Sjlemon for (i = 0; i < len; i++) 26785373Sjlemon cnputc(str[i]); 26885373Sjlemon cnputc('\n'); 26985373Sjlemon} 27085373Sjlemon 27185373Sjlemonstatic int 27285373Sjlemonsysctl_kern_console(SYSCTL_HANDLER_ARGS) 27385373Sjlemon{ 27485373Sjlemon struct cn_device *cnd; 27585373Sjlemon struct consdev *cp, **list; 27685373Sjlemon char *name, *p; 27785373Sjlemon int delete, len, error; 27885373Sjlemon 27985373Sjlemon len = 2; 28085373Sjlemon SET_FOREACH(list, cons_set) { 28185373Sjlemon cp = *list; 28285373Sjlemon if (cp->cn_dev != NULL) 28385373Sjlemon len += strlen(devtoname(cp->cn_dev)) + 1; 28456582Sbde } 28585373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 28685373Sjlemon len += strlen(devtoname(cnd->cnd_cn->cn_dev)) + 1; 28785373Sjlemon len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX; 288111119Simp MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO); 28985373Sjlemon p = name; 29085373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 29185373Sjlemon p += sprintf(p, "%s,", devtoname(cnd->cnd_cn->cn_dev)); 29285373Sjlemon *p++ = '/'; 29385373Sjlemon SET_FOREACH(list, cons_set) { 29485373Sjlemon cp = *list; 29585373Sjlemon if (cp->cn_dev != NULL) 29685373Sjlemon p += sprintf(p, "%s,", devtoname(cp->cn_dev)); 29785373Sjlemon } 29885373Sjlemon error = sysctl_handle_string(oidp, name, len, req); 29985373Sjlemon if (error == 0 && req->newptr != NULL) { 30085373Sjlemon p = name; 30185373Sjlemon error = ENXIO; 30285373Sjlemon delete = 0; 30385373Sjlemon if (*p == '-') { 30485373Sjlemon delete = 1; 30585373Sjlemon p++; 30685373Sjlemon } 30785373Sjlemon SET_FOREACH(list, cons_set) { 30885373Sjlemon cp = *list; 30985373Sjlemon if (cp->cn_dev == NULL || 31085373Sjlemon strcmp(p, devtoname(cp->cn_dev)) != 0) 31185373Sjlemon continue; 31285373Sjlemon if (delete) { 31385373Sjlemon cnremove(cp); 31485373Sjlemon error = 0; 31585373Sjlemon } else { 31685373Sjlemon error = cnadd(cp); 31785373Sjlemon if (error == 0) 31885373Sjlemon cnselect(cp); 31985373Sjlemon } 32085373Sjlemon break; 32185373Sjlemon } 32285373Sjlemon } 32385373Sjlemon FREE(name, M_TEMP); 32485373Sjlemon return (error); 32527982Sjulian} 32627982Sjulian 32785373SjlemonSYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 32885373Sjlemon 0, 0, sysctl_kern_console, "A", "Console device control"); 32985373Sjlemon 33027982Sjulian/* 33127982Sjulian * User has changed the state of the console muting. 33227982Sjulian * This may require us to open or close the device in question. 33327982Sjulian */ 33412675Sjulianstatic int 33562573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 33627982Sjulian{ 33727982Sjulian int error; 33827982Sjulian int ocn_mute; 33927982Sjulian 34027982Sjulian ocn_mute = cn_mute; 34127982Sjulian error = sysctl_handle_int(oidp, &cn_mute, 0, req); 34285373Sjlemon if (error != 0 || req->newptr == NULL) 34385373Sjlemon return (error); 34485373Sjlemon if (ocn_mute && !cn_mute && cn_is_open) 34585373Sjlemon error = cnopen(NODEV, openflag, 0, curthread); 34685373Sjlemon else if (!ocn_mute && cn_mute && cn_is_open) { 34785373Sjlemon error = cnclose(NODEV, openflag, 0, curthread); 34885373Sjlemon cn_is_open = 1; /* XXX hack */ 34927982Sjulian } 35027982Sjulian return (error); 35127982Sjulian} 35227982Sjulian 35327982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 35485373Sjlemon 0, sizeof(cn_mute), sysctl_kern_consmute, "I", ""); 35527982Sjulian 35627982Sjulianstatic int 35785373Sjlemoncn_devopen(struct cn_device *cnd, struct thread *td, int forceopen) 35885373Sjlemon{ 35985373Sjlemon char path[CNDEVPATHMAX]; 36085884Sjlemon struct nameidata nd; 36185884Sjlemon struct vnode *vp; 3624Srgrimes dev_t dev; 36385373Sjlemon int error; 3641007Sdg 36585884Sjlemon if ((vp = cnd->cnd_vp) != NULL) { 36685884Sjlemon if (!forceopen && vp->v_type != VBAD) { 36785884Sjlemon dev = vp->v_rdev; 36885373Sjlemon return ((*devsw(dev)->d_open)(dev, openflag, 0, td)); 36927982Sjulian } 37085373Sjlemon cnd->cnd_vp = NULL; 37191406Sjhb vn_close(vp, openflag, td->td_ucred, td); 3725764Sbde } 373105354Srobert if (cnd->cnd_name[0] == '\0') { 374105354Srobert strlcpy(cnd->cnd_name, devtoname(cnd->cnd_cn->cn_dev), 37585373Sjlemon sizeof(cnd->cnd_name)); 376105354Srobert } 37785373Sjlemon snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_name); 37885373Sjlemon NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); 37985373Sjlemon error = vn_open(&nd, &openflag, 0); 38085373Sjlemon if (error == 0) { 38185373Sjlemon NDFREE(&nd, NDF_ONLY_PNBUF); 38285373Sjlemon VOP_UNLOCK(nd.ni_vp, 0, td); 38385373Sjlemon if (nd.ni_vp->v_type == VCHR) 38485373Sjlemon cnd->cnd_vp = nd.ni_vp; 38585373Sjlemon else 38691406Sjhb vn_close(nd.ni_vp, openflag, td->td_ucred, td); 38785373Sjlemon } 38885373Sjlemon return (cnd->cnd_vp != NULL); 3894Srgrimes} 3908876Srgrimes 39112675Sjulianstatic int 39285373Sjlemoncnopen(dev_t dev, int flag, int mode, struct thread *td) 3934Srgrimes{ 39485373Sjlemon struct cn_device *cnd; 3951007Sdg 39685448Sjlemon openflag = flag | FWRITE; /* XXX */ 39785373Sjlemon cn_is_open = 1; /* console is logically open */ 39885373Sjlemon if (cn_mute) 3994Srgrimes return (0); 40085373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 40185373Sjlemon cn_devopen(cnd, td, 0); 40285373Sjlemon return (0); 40385373Sjlemon} 40485373Sjlemon 40585373Sjlemonstatic int 40685373Sjlemoncnclose(dev_t dev, int flag, int mode, struct thread *td) 40785373Sjlemon{ 40885373Sjlemon struct cn_device *cnd; 40985458Sjlemon struct vnode *vp; 41085373Sjlemon 41185373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 41285458Sjlemon if ((vp = cnd->cnd_vp) == NULL) 41385373Sjlemon continue; 41485373Sjlemon cnd->cnd_vp = NULL; 41591406Sjhb vn_close(vp, openflag, td->td_ucred, td); 4165764Sbde } 41785373Sjlemon cn_is_open = 0; 41827982Sjulian return (0); 4194Srgrimes} 4208876Srgrimes 42112675Sjulianstatic int 42285373Sjlemoncnread(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)) 4284Srgrimes return (0); 42985373Sjlemon dev = cnd->cnd_vp->v_rdev; 43046676Sphk return ((*devsw(dev)->d_read)(dev, uio, flag)); 4314Srgrimes} 4328876Srgrimes 43312675Sjulianstatic int 43485373Sjlemoncnwrite(dev_t dev, struct uio *uio, int flag) 4354Srgrimes{ 43685373Sjlemon struct cn_device *cnd; 43756582Sbde 43885373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 43985373Sjlemon if (cn_mute || CND_INVALID(cnd, curthread)) 44085373Sjlemon goto done; 4411021Sdg if (constty) 4424Srgrimes dev = constty->t_dev; 4434Srgrimes else 44485373Sjlemon dev = cnd->cnd_vp->v_rdev; 44585373Sjlemon if (dev != NULL) { 44685373Sjlemon log_console(uio); 44785373Sjlemon return ((*devsw(dev)->d_write)(dev, uio, flag)); 44885373Sjlemon } 44985373Sjlemondone: 45085373Sjlemon uio->uio_resid = 0; /* dump the data */ 45185373Sjlemon return (0); 4524Srgrimes} 4538876Srgrimes 45412675Sjulianstatic int 45585373Sjlemoncnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 4564Srgrimes{ 45785373Sjlemon struct cn_device *cnd; 4584Srgrimes int error; 4594Srgrimes 46085373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 46185373Sjlemon if (cn_mute || CND_INVALID(cnd, td)) 4624Srgrimes return (0); 4634Srgrimes /* 4644Srgrimes * Superuser can always use this to wrest control of console 4654Srgrimes * output from the "virtual" console. 4664Srgrimes */ 4674Srgrimes if (cmd == TIOCCONS && constty) { 46893593Sjhb error = suser(td); 4694Srgrimes if (error) 4704Srgrimes return (error); 4714Srgrimes constty = NULL; 4724Srgrimes return (0); 4734Srgrimes } 47485373Sjlemon dev = cnd->cnd_vp->v_rdev; 47585373Sjlemon if (dev != NULL) 47685373Sjlemon return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td)); 47785373Sjlemon return (0); 4784Srgrimes} 4794Srgrimes 48085373Sjlemon/* 48185373Sjlemon * XXX 48285373Sjlemon * poll/kqfilter do not appear to be correct 48385373Sjlemon */ 48412675Sjulianstatic int 48585373Sjlemoncnpoll(dev_t dev, int events, struct thread *td) 4864Srgrimes{ 48785373Sjlemon struct cn_device *cnd; 4886712Spst 48985373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 49085373Sjlemon if (cn_mute || CND_INVALID(cnd, td)) 49185373Sjlemon return (0); 49285373Sjlemon dev = cnd->cnd_vp->v_rdev; 49385373Sjlemon if (dev != NULL) 49485373Sjlemon return ((*devsw(dev)->d_poll)(dev, events, td)); 49585373Sjlemon return (0); 4964Srgrimes} 4974Srgrimes 49872521Sjlemonstatic int 49985373Sjlemoncnkqfilter(dev_t dev, struct knote *kn) 50072521Sjlemon{ 50185373Sjlemon struct cn_device *cnd; 50285373Sjlemon 50385373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 50485373Sjlemon if (cn_mute || CND_INVALID(cnd, curthread)) 50572521Sjlemon return (1); 50685373Sjlemon dev = cnd->cnd_vp->v_rdev; 50785373Sjlemon if (dev != NULL) 50872521Sjlemon return ((*devsw(dev)->d_kqfilter)(dev, kn)); 50972521Sjlemon return (1); 51072521Sjlemon} 51172521Sjlemon 51285373Sjlemon/* 51385373Sjlemon * Low level console routines. 51485373Sjlemon */ 515798Swollmanint 51685373Sjlemoncngetc(void) 5174Srgrimes{ 5185160Sjoerg int c; 51985373Sjlemon 52085373Sjlemon if (cn_mute) 52119268Sjulian return (-1); 52285373Sjlemon while ((c = cncheckc()) == -1) 52385373Sjlemon ; 52485373Sjlemon if (c == '\r') 52585373Sjlemon c = '\n'; /* console input is always ICRNL */ 5265160Sjoerg return (c); 5274Srgrimes} 5284Srgrimes 5293728Sphkint 53085373Sjlemoncncheckc(void) 5313728Sphk{ 53285373Sjlemon struct cn_device *cnd; 53385373Sjlemon struct consdev *cn; 53485373Sjlemon int c; 53585373Sjlemon 53685373Sjlemon if (cn_mute) 53718287Sbde return (-1); 53885373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 53985373Sjlemon cn = cnd->cnd_cn; 540111194Sphk c = cn->cn_checkc(cn); 54185373Sjlemon if (c != -1) { 54285373Sjlemon return (c); 54385373Sjlemon } 54485373Sjlemon } 54585373Sjlemon return (-1); 5463728Sphk} 5473728Sphk 548798Swollmanvoid 54985373Sjlemoncnputc(int c) 5504Srgrimes{ 55185373Sjlemon struct cn_device *cnd; 55285373Sjlemon struct consdev *cn; 55387620Sguido char *cp; 55485373Sjlemon 55585373Sjlemon if (cn_mute || c == '\0') 5564Srgrimes return; 55785373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 55885373Sjlemon cn = cnd->cnd_cn; 5594Srgrimes if (c == '\n') 560111194Sphk cn->cn_putc(cn, '\r'); 561111194Sphk cn->cn_putc(cn, c); 5624Srgrimes } 56387649Sguido#ifdef DDB 56487620Sguido if (console_pausing && !db_active && (c == '\n')) { 56587649Sguido#else 56687649Sguido if (console_pausing && (c == '\n')) { 56787649Sguido#endif 56887620Sguido for (cp = console_pausestr; *cp != '\0'; cp++) 56987620Sguido cnputc(*cp); 57087620Sguido if (cngetc() == '.') 57187620Sguido console_pausing = 0; 57287620Sguido cnputc('\r'); 57387620Sguido for (cp = console_pausestr; *cp != '\0'; cp++) 57487620Sguido cnputc(' '); 57587620Sguido cnputc('\r'); 57687620Sguido } 5774Srgrimes} 5784Srgrimes 57955823Syokotavoid 58085373Sjlemoncndbctl(int on) 58155823Syokota{ 58285373Sjlemon struct cn_device *cnd; 58385373Sjlemon struct consdev *cn; 58455823Syokota static int refcount; 58555823Syokota 58655823Syokota if (!on) 58755823Syokota refcount--; 58885373Sjlemon if (refcount == 0) 58985373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 59085373Sjlemon cn = cnd->cnd_cn; 59185373Sjlemon if (cn->cn_dbctl != NULL) 592111194Sphk cn->cn_dbctl(cn, on); 59385373Sjlemon } 59455823Syokota if (on) 59555823Syokota refcount++; 59655823Syokota} 597112046Sphk 598116663Siedowsestatic int consmsgbuf_size = 8192; 599116663SiedowseSYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 600116663Siedowse ""); 601116663Siedowse 602116663Siedowse/* 603116663Siedowse * Redirect console output to a tty. 604116663Siedowse */ 605116663Siedowsevoid 606116663Siedowseconstty_set(struct tty *tp) 607116663Siedowse{ 608116663Siedowse int size; 609116663Siedowse 610116663Siedowse KASSERT(tp != NULL, ("constty_set: NULL tp")); 611116663Siedowse if (consbuf == NULL) { 612116663Siedowse size = consmsgbuf_size; 613116663Siedowse consbuf = malloc(size, M_TTYS, M_WAITOK); 614116663Siedowse msgbuf_init(&consmsgbuf, consbuf, size); 615116663Siedowse callout_init(&conscallout, 0); 616116663Siedowse } 617116663Siedowse constty = tp; 618116663Siedowse constty_timeout(NULL); 619116663Siedowse} 620116663Siedowse 621116663Siedowse/* 622116663Siedowse * Disable console redirection to a tty. 623116663Siedowse */ 624116663Siedowsevoid 625116663Siedowseconstty_clear(void) 626116663Siedowse{ 627116663Siedowse int c; 628116663Siedowse 629116663Siedowse constty = NULL; 630116663Siedowse if (consbuf == NULL) 631116663Siedowse return; 632116663Siedowse callout_stop(&conscallout); 633116663Siedowse while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 634116663Siedowse cnputc(c); 635116663Siedowse free(consbuf, M_TTYS); 636116663Siedowse consbuf = NULL; 637116663Siedowse} 638116663Siedowse 639116663Siedowse/* Times per second to check for pending console tty messages. */ 640116663Siedowsestatic int constty_wakeups_per_second = 5; 641116663SiedowseSYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 642116663Siedowse &constty_wakeups_per_second, 0, ""); 643116663Siedowse 644112046Sphkstatic void 645116663Siedowseconstty_timeout(void *arg) 646116663Siedowse{ 647116663Siedowse int c; 648116663Siedowse 649116663Siedowse while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) { 650116663Siedowse if (tputchar(c, constty) < 0) 651116663Siedowse constty = NULL; 652116663Siedowse } 653116663Siedowse if (constty != NULL) { 654116663Siedowse callout_reset(&conscallout, hz / constty_wakeups_per_second, 655116663Siedowse constty_timeout, NULL); 656116663Siedowse } else { 657116663Siedowse /* Deallocate the constty buffer memory. */ 658116663Siedowse constty_clear(); 659116663Siedowse } 660116663Siedowse} 661116663Siedowse 662116663Siedowsestatic void 663112046Sphkcn_drvinit(void *unused) 664112046Sphk{ 665112046Sphk 666112046Sphk make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "console"); 667112046Sphk} 668112046Sphk 669112046SphkSYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL) 670