kern_cons.c revision 125467
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 125467 2004-02-05 01:56:43Z kan $"); 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 struct vnode *cnd_vp; 9685373Sjlemon struct consdev *cnd_cn; 9785373Sjlemon}; 9885373Sjlemon 9985373Sjlemon#define CNDEVPATHMAX 32 10085373Sjlemon#define CNDEVTAB_SIZE 4 10185373Sjlemonstatic struct cn_device cn_devtab[CNDEVTAB_SIZE]; 10285373Sjlemonstatic STAILQ_HEAD(, cn_device) cn_devlist = 10385373Sjlemon STAILQ_HEAD_INITIALIZER(cn_devlist); 10485373Sjlemon 10585373Sjlemon#define CND_INVALID(cnd, td) \ 10685373Sjlemon (cnd == NULL || cnd->cnd_vp == NULL || \ 10785373Sjlemon (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1))) 10885373Sjlemon 10949049Syokotastatic udev_t cn_udev_t; 11041612SeivindSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 11149049Syokota &cn_udev_t, sizeof cn_udev_t, "T,dev_t", ""); 11227982Sjulian 113125467Skanint cons_avail_mask = 0; /* Bit mask. Each registered low level console 114125467Skan * which is currently unavailable for inpit 115125467Skan * (i.e., if it is in graphics mode) will have 116125467Skan * this bit cleared. 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; 212120456Sphk if (cn->cn_name[0] == '\0') { 213120456Sphk /* XXX: it is unclear if/where this print might output */ 214120456Sphk printf("WARNING: console at %p has no name\n", cn); 215120456Sphk } 21685373Sjlemon STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 217125467Skan 218125467Skan /* Add device to the active mask. */ 219125467Skan cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 220125467Skan 22185373Sjlemon return (0); 22210665Sbde} 22310665Sbde 22410665Sbdevoid 22585373Sjlemoncnremove(struct consdev *cn) 22610665Sbde{ 22785373Sjlemon struct cn_device *cnd; 228125467Skan int i; 22910665Sbde 23085373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 23185373Sjlemon if (cnd->cnd_cn != cn) 23285373Sjlemon continue; 23385373Sjlemon STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 23485373Sjlemon if (cnd->cnd_vp != NULL) 23585373Sjlemon vn_close(cnd->cnd_vp, openflag, NOCRED, NULL); 23685373Sjlemon cnd->cnd_vp = NULL; 23785373Sjlemon cnd->cnd_cn = NULL; 238125467Skan 239125467Skan /* Remove this device from available mask. */ 240125467Skan for (i = 0; i < CNDEVTAB_SIZE; i++) 241125467Skan if (cnd == &cn_devtab[i]) { 242125467Skan cons_avail_mask &= ~(1 << i); 243125467Skan break; 244125467Skan } 24585373Sjlemon#if 0 24685373Sjlemon /* 24785373Sjlemon * XXX 24885373Sjlemon * syscons gets really confused if console resources are 24985373Sjlemon * freed after the system has initialized. 25085373Sjlemon */ 25185373Sjlemon if (cn->cn_term != NULL) 25285373Sjlemon cn->cn_term(cn); 25385373Sjlemon#endif 25410665Sbde return; 25556582Sbde } 2564Srgrimes} 2574Srgrimes 25885373Sjlemonvoid 25985373Sjlemoncnselect(struct consdev *cn) 26027982Sjulian{ 26185373Sjlemon struct cn_device *cnd; 26227982Sjulian 26385373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 26485373Sjlemon if (cnd->cnd_cn != cn) 26585373Sjlemon continue; 26685373Sjlemon if (cnd == STAILQ_FIRST(&cn_devlist)) 26785373Sjlemon return; 26885373Sjlemon STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 26985373Sjlemon STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 27027982Sjulian return; 27185373Sjlemon } 27285373Sjlemon} 27327982Sjulian 27485373Sjlemonvoid 275125467Skancnavailable(struct consdev *cn, int available) 276125467Skan{ 277125467Skan int i; 278125467Skan 279125467Skan for (i = 0; i < CNDEVTAB_SIZE; i++) { 280125467Skan if (cn_devtab[i].cnd_cn == cn) 281125467Skan break; 282125467Skan } 283125467Skan if (available) { 284125467Skan if (i < CNDEVTAB_SIZE) 285125467Skan cons_avail_mask |= (1 << i); 286125467Skan cn->cn_flags &= ~CN_FLAG_NOAVAIL; 287125467Skan } else { 288125467Skan if (i < CNDEVTAB_SIZE) 289125467Skan cons_avail_mask &= ~(1 << i); 290125467Skan cn->cn_flags |= CN_FLAG_NOAVAIL; 291125467Skan } 292125467Skan} 293125467Skan 294125467Skanint 295125467Skancn_unavailable(void) 296125467Skan{ 297125467Skan return (cons_avail_mask == 0); 298125467Skan} 299125467Skan 300125467Skanvoid 30185373Sjlemoncndebug(char *str) 30285373Sjlemon{ 30385373Sjlemon int i, len; 30485373Sjlemon 30585373Sjlemon len = strlen(str); 30685373Sjlemon cnputc('>'); cnputc('>'); cnputc('>'); cnputc(' '); 30785373Sjlemon for (i = 0; i < len; i++) 30885373Sjlemon cnputc(str[i]); 30985373Sjlemon cnputc('\n'); 31085373Sjlemon} 31185373Sjlemon 312120456Sphk/* 313120456Sphk * XXX: rewrite to use sbufs instead 314120456Sphk */ 315120456Sphk 31685373Sjlemonstatic int 31785373Sjlemonsysctl_kern_console(SYSCTL_HANDLER_ARGS) 31885373Sjlemon{ 31985373Sjlemon struct cn_device *cnd; 32085373Sjlemon struct consdev *cp, **list; 32185373Sjlemon char *name, *p; 32285373Sjlemon int delete, len, error; 32385373Sjlemon 32485373Sjlemon len = 2; 32585373Sjlemon SET_FOREACH(list, cons_set) { 32685373Sjlemon cp = *list; 327120456Sphk if (cp->cn_name[0] != '\0') 328120456Sphk len += strlen(cp->cn_name) + 1; 32956582Sbde } 33085373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 331120456Sphk len += strlen(cnd->cnd_cn->cn_name) + 1; 33285373Sjlemon len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX; 333111119Simp MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO); 33485373Sjlemon p = name; 33585373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 336120456Sphk p += sprintf(p, "%s,", cnd->cnd_cn->cn_name); 33785373Sjlemon *p++ = '/'; 33885373Sjlemon SET_FOREACH(list, cons_set) { 33985373Sjlemon cp = *list; 340120456Sphk if (cp->cn_name[0] != '\0') 341120456Sphk p += sprintf(p, "%s,", cp->cn_name); 34285373Sjlemon } 34385373Sjlemon error = sysctl_handle_string(oidp, name, len, req); 34485373Sjlemon if (error == 0 && req->newptr != NULL) { 34585373Sjlemon p = name; 34685373Sjlemon error = ENXIO; 34785373Sjlemon delete = 0; 34885373Sjlemon if (*p == '-') { 34985373Sjlemon delete = 1; 35085373Sjlemon p++; 35185373Sjlemon } 35285373Sjlemon SET_FOREACH(list, cons_set) { 35385373Sjlemon cp = *list; 354120456Sphk if (strcmp(p, cp->cn_name) != 0) 35585373Sjlemon continue; 35685373Sjlemon if (delete) { 35785373Sjlemon cnremove(cp); 35885373Sjlemon error = 0; 35985373Sjlemon } else { 36085373Sjlemon error = cnadd(cp); 36185373Sjlemon if (error == 0) 36285373Sjlemon cnselect(cp); 36385373Sjlemon } 36485373Sjlemon break; 36585373Sjlemon } 36685373Sjlemon } 36785373Sjlemon FREE(name, M_TEMP); 36885373Sjlemon return (error); 36927982Sjulian} 37027982Sjulian 37185373SjlemonSYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 37285373Sjlemon 0, 0, sysctl_kern_console, "A", "Console device control"); 37385373Sjlemon 37427982Sjulian/* 37527982Sjulian * User has changed the state of the console muting. 37627982Sjulian * This may require us to open or close the device in question. 37727982Sjulian */ 37812675Sjulianstatic int 37962573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 38027982Sjulian{ 38127982Sjulian int error; 38227982Sjulian int ocn_mute; 38327982Sjulian 38427982Sjulian ocn_mute = cn_mute; 38527982Sjulian error = sysctl_handle_int(oidp, &cn_mute, 0, req); 38685373Sjlemon if (error != 0 || req->newptr == NULL) 38785373Sjlemon return (error); 38885373Sjlemon if (ocn_mute && !cn_mute && cn_is_open) 38985373Sjlemon error = cnopen(NODEV, openflag, 0, curthread); 39085373Sjlemon else if (!ocn_mute && cn_mute && cn_is_open) { 39185373Sjlemon error = cnclose(NODEV, openflag, 0, curthread); 39285373Sjlemon cn_is_open = 1; /* XXX hack */ 39327982Sjulian } 39427982Sjulian return (error); 39527982Sjulian} 39627982Sjulian 39727982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 39885373Sjlemon 0, sizeof(cn_mute), sysctl_kern_consmute, "I", ""); 39927982Sjulian 40027982Sjulianstatic int 40185373Sjlemoncn_devopen(struct cn_device *cnd, struct thread *td, int forceopen) 40285373Sjlemon{ 40385373Sjlemon char path[CNDEVPATHMAX]; 40485884Sjlemon struct nameidata nd; 40585884Sjlemon struct vnode *vp; 4064Srgrimes dev_t dev; 40785373Sjlemon int error; 4081007Sdg 40985884Sjlemon if ((vp = cnd->cnd_vp) != NULL) { 41085884Sjlemon if (!forceopen && vp->v_type != VBAD) { 41185884Sjlemon dev = vp->v_rdev; 41285373Sjlemon return ((*devsw(dev)->d_open)(dev, openflag, 0, td)); 41327982Sjulian } 41485373Sjlemon cnd->cnd_vp = NULL; 41591406Sjhb vn_close(vp, openflag, td->td_ucred, td); 4165764Sbde } 417120456Sphk snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_cn->cn_name); 41885373Sjlemon NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); 419118094Sphk error = vn_open(&nd, &openflag, 0, -1); 42085373Sjlemon if (error == 0) { 42185373Sjlemon NDFREE(&nd, NDF_ONLY_PNBUF); 42285373Sjlemon VOP_UNLOCK(nd.ni_vp, 0, td); 42385373Sjlemon if (nd.ni_vp->v_type == VCHR) 42485373Sjlemon cnd->cnd_vp = nd.ni_vp; 42585373Sjlemon else 42691406Sjhb vn_close(nd.ni_vp, openflag, td->td_ucred, td); 42785373Sjlemon } 42885373Sjlemon return (cnd->cnd_vp != NULL); 4294Srgrimes} 4308876Srgrimes 43112675Sjulianstatic int 43285373Sjlemoncnopen(dev_t dev, int flag, int mode, struct thread *td) 4334Srgrimes{ 43485373Sjlemon struct cn_device *cnd; 4351007Sdg 43685448Sjlemon openflag = flag | FWRITE; /* XXX */ 43785373Sjlemon cn_is_open = 1; /* console is logically open */ 43885373Sjlemon if (cn_mute) 4394Srgrimes return (0); 44085373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 44185373Sjlemon cn_devopen(cnd, td, 0); 44285373Sjlemon return (0); 44385373Sjlemon} 44485373Sjlemon 44585373Sjlemonstatic int 44685373Sjlemoncnclose(dev_t dev, int flag, int mode, struct thread *td) 44785373Sjlemon{ 44885373Sjlemon struct cn_device *cnd; 44985458Sjlemon struct vnode *vp; 45085373Sjlemon 45185373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 45285458Sjlemon if ((vp = cnd->cnd_vp) == NULL) 45385373Sjlemon continue; 45485373Sjlemon cnd->cnd_vp = NULL; 45591406Sjhb vn_close(vp, openflag, td->td_ucred, td); 4565764Sbde } 45785373Sjlemon cn_is_open = 0; 45827982Sjulian return (0); 4594Srgrimes} 4608876Srgrimes 46112675Sjulianstatic int 46285373Sjlemoncnread(dev_t dev, struct uio *uio, int flag) 4634Srgrimes{ 46485373Sjlemon struct cn_device *cnd; 46556582Sbde 46685373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 46785373Sjlemon if (cn_mute || CND_INVALID(cnd, curthread)) 4684Srgrimes return (0); 46985373Sjlemon dev = cnd->cnd_vp->v_rdev; 47046676Sphk return ((*devsw(dev)->d_read)(dev, uio, flag)); 4714Srgrimes} 4728876Srgrimes 47312675Sjulianstatic int 47485373Sjlemoncnwrite(dev_t dev, struct uio *uio, int flag) 4754Srgrimes{ 47685373Sjlemon struct cn_device *cnd; 47756582Sbde 47885373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 47985373Sjlemon if (cn_mute || CND_INVALID(cnd, curthread)) 48085373Sjlemon goto done; 4811021Sdg if (constty) 4824Srgrimes dev = constty->t_dev; 4834Srgrimes else 48485373Sjlemon dev = cnd->cnd_vp->v_rdev; 48585373Sjlemon if (dev != NULL) { 48685373Sjlemon log_console(uio); 48785373Sjlemon return ((*devsw(dev)->d_write)(dev, uio, flag)); 48885373Sjlemon } 48985373Sjlemondone: 49085373Sjlemon uio->uio_resid = 0; /* dump the data */ 49185373Sjlemon return (0); 4924Srgrimes} 4938876Srgrimes 49412675Sjulianstatic int 49585373Sjlemoncnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 4964Srgrimes{ 49785373Sjlemon struct cn_device *cnd; 4984Srgrimes int error; 4994Srgrimes 50085373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 50185373Sjlemon if (cn_mute || CND_INVALID(cnd, td)) 5024Srgrimes return (0); 5034Srgrimes /* 5044Srgrimes * Superuser can always use this to wrest control of console 5054Srgrimes * output from the "virtual" console. 5064Srgrimes */ 5074Srgrimes if (cmd == TIOCCONS && constty) { 50893593Sjhb error = suser(td); 5094Srgrimes if (error) 5104Srgrimes return (error); 5114Srgrimes constty = NULL; 5124Srgrimes return (0); 5134Srgrimes } 51485373Sjlemon dev = cnd->cnd_vp->v_rdev; 51585373Sjlemon if (dev != NULL) 51685373Sjlemon return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td)); 51785373Sjlemon return (0); 5184Srgrimes} 5194Srgrimes 52085373Sjlemon/* 52185373Sjlemon * XXX 52285373Sjlemon * poll/kqfilter do not appear to be correct 52385373Sjlemon */ 52412675Sjulianstatic int 52585373Sjlemoncnpoll(dev_t dev, int events, struct thread *td) 5264Srgrimes{ 52785373Sjlemon struct cn_device *cnd; 5286712Spst 52985373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 53085373Sjlemon if (cn_mute || CND_INVALID(cnd, td)) 53185373Sjlemon return (0); 53285373Sjlemon dev = cnd->cnd_vp->v_rdev; 53385373Sjlemon if (dev != NULL) 53485373Sjlemon return ((*devsw(dev)->d_poll)(dev, events, td)); 53585373Sjlemon return (0); 5364Srgrimes} 5374Srgrimes 53872521Sjlemonstatic int 53985373Sjlemoncnkqfilter(dev_t dev, struct knote *kn) 54072521Sjlemon{ 54185373Sjlemon struct cn_device *cnd; 54285373Sjlemon 54385373Sjlemon cnd = STAILQ_FIRST(&cn_devlist); 54485373Sjlemon if (cn_mute || CND_INVALID(cnd, curthread)) 54572521Sjlemon return (1); 54685373Sjlemon dev = cnd->cnd_vp->v_rdev; 54785373Sjlemon if (dev != NULL) 54872521Sjlemon return ((*devsw(dev)->d_kqfilter)(dev, kn)); 54972521Sjlemon return (1); 55072521Sjlemon} 55172521Sjlemon 55285373Sjlemon/* 55385373Sjlemon * Low level console routines. 55485373Sjlemon */ 555798Swollmanint 55685373Sjlemoncngetc(void) 5574Srgrimes{ 5585160Sjoerg int c; 55985373Sjlemon 56085373Sjlemon if (cn_mute) 56119268Sjulian return (-1); 56285373Sjlemon while ((c = cncheckc()) == -1) 56385373Sjlemon ; 56485373Sjlemon if (c == '\r') 56585373Sjlemon c = '\n'; /* console input is always ICRNL */ 5665160Sjoerg return (c); 5674Srgrimes} 5684Srgrimes 5693728Sphkint 57085373Sjlemoncncheckc(void) 5713728Sphk{ 57285373Sjlemon struct cn_device *cnd; 57385373Sjlemon struct consdev *cn; 57485373Sjlemon int c; 57585373Sjlemon 57685373Sjlemon if (cn_mute) 57718287Sbde return (-1); 57885373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 57985373Sjlemon cn = cnd->cnd_cn; 580121183Srwatson#ifdef DDB 581121204Sphk if (!db_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 582121183Srwatson#endif 583121182Srwatson c = cn->cn_checkc(cn); 584121182Srwatson if (c != -1) { 585121182Srwatson return (c); 586121182Srwatson } 587121183Srwatson#ifdef DDB 58885373Sjlemon } 589121183Srwatson#endif 59085373Sjlemon } 59185373Sjlemon return (-1); 5923728Sphk} 5933728Sphk 594798Swollmanvoid 59585373Sjlemoncnputc(int c) 5964Srgrimes{ 59785373Sjlemon struct cn_device *cnd; 59885373Sjlemon struct consdev *cn; 59987620Sguido char *cp; 60085373Sjlemon 60185373Sjlemon if (cn_mute || c == '\0') 6024Srgrimes return; 60385373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 60485373Sjlemon cn = cnd->cnd_cn; 605121183Srwatson#ifdef DDB 606121204Sphk if (!db_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 607121183Srwatson#endif 608121182Srwatson if (c == '\n') 609121182Srwatson cn->cn_putc(cn, '\r'); 610121182Srwatson cn->cn_putc(cn, c); 611121183Srwatson#ifdef DDB 612121182Srwatson } 613121183Srwatson#endif 6144Srgrimes } 61587649Sguido#ifdef DDB 61687620Sguido if (console_pausing && !db_active && (c == '\n')) { 61787649Sguido#else 61887649Sguido if (console_pausing && (c == '\n')) { 61987649Sguido#endif 62087620Sguido for (cp = console_pausestr; *cp != '\0'; cp++) 62187620Sguido cnputc(*cp); 62287620Sguido if (cngetc() == '.') 62387620Sguido console_pausing = 0; 62487620Sguido cnputc('\r'); 62587620Sguido for (cp = console_pausestr; *cp != '\0'; cp++) 62687620Sguido cnputc(' '); 62787620Sguido cnputc('\r'); 62887620Sguido } 6294Srgrimes} 6304Srgrimes 63155823Syokotavoid 63285373Sjlemoncndbctl(int on) 63355823Syokota{ 63485373Sjlemon struct cn_device *cnd; 63585373Sjlemon struct consdev *cn; 63655823Syokota static int refcount; 63755823Syokota 63855823Syokota if (!on) 63955823Syokota refcount--; 64085373Sjlemon if (refcount == 0) 64185373Sjlemon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 64285373Sjlemon cn = cnd->cnd_cn; 64385373Sjlemon if (cn->cn_dbctl != NULL) 644111194Sphk cn->cn_dbctl(cn, on); 64585373Sjlemon } 64655823Syokota if (on) 64755823Syokota refcount++; 64855823Syokota} 649112046Sphk 650116663Siedowsestatic int consmsgbuf_size = 8192; 651116663SiedowseSYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 652116663Siedowse ""); 653116663Siedowse 654116663Siedowse/* 655116663Siedowse * Redirect console output to a tty. 656116663Siedowse */ 657116663Siedowsevoid 658116663Siedowseconstty_set(struct tty *tp) 659116663Siedowse{ 660116663Siedowse int size; 661116663Siedowse 662116663Siedowse KASSERT(tp != NULL, ("constty_set: NULL tp")); 663116663Siedowse if (consbuf == NULL) { 664116663Siedowse size = consmsgbuf_size; 665116663Siedowse consbuf = malloc(size, M_TTYS, M_WAITOK); 666116663Siedowse msgbuf_init(&consmsgbuf, consbuf, size); 667116663Siedowse callout_init(&conscallout, 0); 668116663Siedowse } 669116663Siedowse constty = tp; 670116663Siedowse constty_timeout(NULL); 671116663Siedowse} 672116663Siedowse 673116663Siedowse/* 674116663Siedowse * Disable console redirection to a tty. 675116663Siedowse */ 676116663Siedowsevoid 677116663Siedowseconstty_clear(void) 678116663Siedowse{ 679116663Siedowse int c; 680116663Siedowse 681116663Siedowse constty = NULL; 682116663Siedowse if (consbuf == NULL) 683116663Siedowse return; 684116663Siedowse callout_stop(&conscallout); 685116663Siedowse while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 686116663Siedowse cnputc(c); 687116663Siedowse free(consbuf, M_TTYS); 688116663Siedowse consbuf = NULL; 689116663Siedowse} 690116663Siedowse 691116663Siedowse/* Times per second to check for pending console tty messages. */ 692116663Siedowsestatic int constty_wakeups_per_second = 5; 693116663SiedowseSYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 694116663Siedowse &constty_wakeups_per_second, 0, ""); 695116663Siedowse 696112046Sphkstatic void 697116663Siedowseconstty_timeout(void *arg) 698116663Siedowse{ 699116663Siedowse int c; 700116663Siedowse 701116663Siedowse while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) { 702116663Siedowse if (tputchar(c, constty) < 0) 703116663Siedowse constty = NULL; 704116663Siedowse } 705116663Siedowse if (constty != NULL) { 706116663Siedowse callout_reset(&conscallout, hz / constty_wakeups_per_second, 707116663Siedowse constty_timeout, NULL); 708116663Siedowse } else { 709116663Siedowse /* Deallocate the constty buffer memory. */ 710116663Siedowse constty_clear(); 711116663Siedowse } 712116663Siedowse} 713116663Siedowse 714116663Siedowsestatic void 715112046Sphkcn_drvinit(void *unused) 716112046Sphk{ 717112046Sphk 718112046Sphk make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "console"); 719112046Sphk} 720112046Sphk 721112046SphkSYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL) 722