kern_cons.c revision 62573
14Srgrimes/* 24Srgrimes * Copyright (c) 1988 University of Utah. 34Srgrimes * Copyright (c) 1991 The Regents of the University of California. 44Srgrimes * All rights reserved. 54Srgrimes * 64Srgrimes * This code is derived from software contributed to Berkeley by 74Srgrimes * the Systems Programming Group of the University of Utah Computer 84Srgrimes * Science Department. 94Srgrimes * 104Srgrimes * Redistribution and use in source and binary forms, with or without 114Srgrimes * modification, are permitted provided that the following conditions 124Srgrimes * are met: 134Srgrimes * 1. Redistributions of source code must retain the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer. 154Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 164Srgrimes * notice, this list of conditions and the following disclaimer in the 174Srgrimes * documentation and/or other materials provided with the distribution. 184Srgrimes * 3. All advertising materials mentioning features or use of this software 194Srgrimes * must display the following acknowledgement: 204Srgrimes * This product includes software developed by the University of 214Srgrimes * California, Berkeley and its contributors. 224Srgrimes * 4. Neither the name of the University nor the names of its contributors 234Srgrimes * may be used to endorse or promote products derived from this software 244Srgrimes * without specific prior written permission. 254Srgrimes * 264Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 274Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 284Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 294Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 304Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 314Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 324Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 334Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 344Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 354Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 364Srgrimes * SUCH DAMAGE. 374Srgrimes * 38620Srgrimes * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 3950477Speter * $FreeBSD: head/sys/kern/tty_cons.c 62573 2000-07-04 11:25:35Z phk $ 404Srgrimes */ 414Srgrimes 422056Swollman#include <sys/param.h> 431549Srgrimes#include <sys/systm.h> 445764Sbde#include <sys/conf.h> 4556525Sbde#include <sys/cons.h> 4612675Sjulian#include <sys/kernel.h> 4718951Sjulian#include <sys/reboot.h> 4812701Sphk#include <sys/sysctl.h> 492056Swollman#include <sys/proc.h> 502056Swollman#include <sys/tty.h> 5134924Sbde#include <sys/uio.h> 524Srgrimes 5312701Sphk#include <machine/cpu.h> 544Srgrimes 5512675Sjulianstatic d_open_t cnopen; 5612675Sjulianstatic d_close_t cnclose; 5712675Sjulianstatic d_read_t cnread; 5812675Sjulianstatic d_write_t cnwrite; 5912675Sjulianstatic d_ioctl_t cnioctl; 6029368Speterstatic d_poll_t cnpoll; 6112675Sjulian 6238485Sbde#define CDEV_MAJOR 0 6347625Sphkstatic struct cdevsw cn_cdevsw = { 6447625Sphk /* open */ cnopen, 6547625Sphk /* close */ cnclose, 6647625Sphk /* read */ cnread, 6747625Sphk /* write */ cnwrite, 6847625Sphk /* ioctl */ cnioctl, 6947625Sphk /* poll */ cnpoll, 7047625Sphk /* mmap */ nommap, 7147625Sphk /* strategy */ nostrategy, 7247625Sphk /* name */ "console", 7347625Sphk /* maj */ CDEV_MAJOR, 7447625Sphk /* dump */ nodump, 7547625Sphk /* psize */ nopsize, 7647625Sphk /* flags */ D_TTY, 7747625Sphk /* bmaj */ -1 7838485Sbde}; 7912675Sjulian 8027982Sjulianstatic dev_t cn_dev_t; /* seems to be never really used */ 8149049Syokotastatic udev_t cn_udev_t; 8241612SeivindSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 8349049Syokota &cn_udev_t, sizeof cn_udev_t, "T,dev_t", ""); 8427982Sjulian 8518951Sjulianstatic int cn_mute; 8612701Sphk 877680Sjoergint cons_unavail = 0; /* XXX: 887680Sjoerg * physical console not available for 897680Sjoerg * input (i.e., it is in graphics mode) 907680Sjoerg */ 914Srgrimes 9227982Sjulianstatic u_char cn_is_open; /* nonzero if logical console is open */ 9327982Sjulianstatic int openmode, openflag; /* how /dev/console was openned */ 9456525Sbdestatic dev_t cn_devfsdev; /* represents the device private info */ 9527982Sjulianstatic u_char cn_phys_is_open; /* nonzero if physical device is open */ 965764Sbdestatic d_close_t *cn_phys_close; /* physical device close function */ 9727982Sjulianstatic d_open_t *cn_phys_open; /* physical device open function */ 9856525Sbde struct consdev *cn_tab; /* physical console device info */ 995764Sbde 10055823SyokotaCONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 10142373Syokota 102798Swollmanvoid 1034Srgrimescninit() 1044Srgrimes{ 10556525Sbde struct consdev *best_cp, *cp, **list; 1064Srgrimes 1074Srgrimes /* 10810665Sbde * Find the first console with the highest priority. 1094Srgrimes */ 11010665Sbde best_cp = NULL; 11148242Speter list = (struct consdev **)cons_set.ls_items; 11242373Syokota while ((cp = *list++) != NULL) { 11342373Syokota if (cp->cn_probe == NULL) 11442373Syokota continue; 1154Srgrimes (*cp->cn_probe)(cp); 1164Srgrimes if (cp->cn_pri > CN_DEAD && 11710665Sbde (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 11810665Sbde best_cp = cp; 1194Srgrimes } 12010665Sbde 1214Srgrimes /* 12218951Sjulian * Check if we should mute the console (for security reasons perhaps) 12318951Sjulian * It can be changes dynamically using sysctl kern.consmute 12418951Sjulian * once we are up and going. 12518951Sjulian * 12618951Sjulian */ 12718951Sjulian cn_mute = ((boothowto & (RB_MUTE 12818951Sjulian |RB_SINGLE 12918951Sjulian |RB_VERBOSE 13018951Sjulian |RB_ASKNAME 13118951Sjulian |RB_CONFIG)) == RB_MUTE); 13218951Sjulian 13318951Sjulian /* 13410665Sbde * If no console, give up. 1354Srgrimes */ 13610665Sbde if (best_cp == NULL) { 13748104Syokota if (cn_tab != NULL && cn_tab->cn_term != NULL) 13848104Syokota (*cn_tab->cn_term)(cn_tab); 13910665Sbde cn_tab = best_cp; 1404Srgrimes return; 14110665Sbde } 14210665Sbde 1434Srgrimes /* 14410665Sbde * Initialize console, then attach to it. This ordering allows 14510665Sbde * debugging using the previous console, if any. 14610665Sbde */ 14710665Sbde (*best_cp->cn_init)(best_cp); 14848104Syokota if (cn_tab != NULL && cn_tab != best_cp) { 14948104Syokota /* Turn off the previous console. */ 15048104Syokota if (cn_tab->cn_term != NULL) 15148104Syokota (*cn_tab->cn_term)(cn_tab); 15248104Syokota } 15310665Sbde cn_tab = best_cp; 15410665Sbde} 15510665Sbde 15610665Sbdevoid 15710665Sbdecninit_finish() 15810665Sbde{ 15910665Sbde struct cdevsw *cdp; 16010665Sbde 16127982Sjulian if ((cn_tab == NULL) || cn_mute) 16210665Sbde return; 16310665Sbde 16410665Sbde /* 1655764Sbde * Hook the open and close functions. 1665764Sbde */ 16746676Sphk cdp = devsw(cn_tab->cn_dev); 16856582Sbde if (cdp != NULL) { 16956582Sbde cn_phys_close = cdp->d_close; 17056582Sbde cdp->d_close = cnclose; 17156582Sbde cn_phys_open = cdp->d_open; 17256582Sbde cdp->d_open = cnopen; 17356582Sbde } 17449049Syokota cn_dev_t = cn_tab->cn_dev; 17549049Syokota cn_udev_t = dev2udev(cn_dev_t); 1764Srgrimes} 1774Srgrimes 17827983Sjulianstatic void 17927983Sjuliancnuninit(void) 18027982Sjulian{ 18127982Sjulian struct cdevsw *cdp; 18227982Sjulian 18327982Sjulian if (cn_tab == NULL) 18427982Sjulian return; 18527982Sjulian 18627982Sjulian /* 18727982Sjulian * Unhook the open and close functions. 18827982Sjulian */ 18946676Sphk cdp = devsw(cn_tab->cn_dev); 19056582Sbde if (cdp != NULL) { 19156582Sbde cdp->d_close = cn_phys_close; 19256582Sbde cdp->d_open = cn_phys_open; 19356582Sbde } 19427982Sjulian cn_phys_close = NULL; 19527982Sjulian cn_phys_open = NULL; 19649049Syokota cn_dev_t = NODEV; 19749049Syokota cn_udev_t = NOUDEV; 19827982Sjulian} 19927982Sjulian 20027982Sjulian/* 20127982Sjulian * User has changed the state of the console muting. 20227982Sjulian * This may require us to open or close the device in question. 20327982Sjulian */ 20412675Sjulianstatic int 20562573Sphksysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 20627982Sjulian{ 20727982Sjulian int error; 20827982Sjulian int ocn_mute; 20927982Sjulian 21027982Sjulian ocn_mute = cn_mute; 21127982Sjulian error = sysctl_handle_int(oidp, &cn_mute, 0, req); 21227982Sjulian if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { 21327982Sjulian if(ocn_mute && !cn_mute) { 21427982Sjulian /* 21527982Sjulian * going from muted to unmuted.. open the physical dev 21627982Sjulian * if the console has been openned 21727982Sjulian */ 21827982Sjulian cninit_finish(); 21927982Sjulian if(cn_is_open) 22027982Sjulian /* XXX curproc is not what we want really */ 22127982Sjulian error = cnopen(cn_dev_t, openflag, 22227982Sjulian openmode, curproc); 22327982Sjulian /* if it failed, back it out */ 22427982Sjulian if ( error != 0) cnuninit(); 22527982Sjulian } else if (!ocn_mute && cn_mute) { 22627982Sjulian /* 22727982Sjulian * going from unmuted to muted.. close the physical dev 22827982Sjulian * if it's only open via /dev/console 22927982Sjulian */ 23027982Sjulian if(cn_is_open) 23127982Sjulian error = cnclose(cn_dev_t, openflag, 23227982Sjulian openmode, curproc); 23327982Sjulian if ( error == 0) cnuninit(); 23427982Sjulian } 23527982Sjulian if (error != 0) { 23627982Sjulian /* 23727982Sjulian * back out the change if there was an error 23827982Sjulian */ 23927982Sjulian cn_mute = ocn_mute; 24027982Sjulian } 24127982Sjulian } 24227982Sjulian return (error); 24327982Sjulian} 24427982Sjulian 24527982SjulianSYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 24627982Sjulian 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); 24727982Sjulian 24827982Sjulianstatic int 2494Srgrimescnopen(dev, flag, mode, p) 2504Srgrimes dev_t dev; 2514Srgrimes int flag, mode; 2524Srgrimes struct proc *p; 2534Srgrimes{ 2545764Sbde dev_t cndev, physdev; 25527982Sjulian int retval = 0; 2561007Sdg 25756582Sbde if (cn_tab == NULL || cn_phys_open == NULL) 2584Srgrimes return (0); 2595764Sbde cndev = cn_tab->cn_dev; 2605764Sbde physdev = (major(dev) == major(cndev) ? dev : cndev); 26127982Sjulian /* 26227982Sjulian * If mute is active, then non console opens don't get here 26327982Sjulian * so we don't need to check for that. They 26427982Sjulian * bypass this and go straight to the device. 26527982Sjulian */ 26627982Sjulian if(!cn_mute) 26727982Sjulian retval = (*cn_phys_open)(physdev, flag, mode, p); 2685764Sbde if (retval == 0) { 26927982Sjulian /* 27027982Sjulian * check if we openned it via /dev/console or 27127982Sjulian * via the physical entry (e.g. /dev/sio0). 27227982Sjulian */ 2735764Sbde if (dev == cndev) 2745764Sbde cn_phys_is_open = 1; 27527982Sjulian else if (physdev == cndev) { 27627982Sjulian openmode = mode; 27727982Sjulian openflag = flag; 2785764Sbde cn_is_open = 1; 27927982Sjulian } 28051654Sphk dev->si_tty = physdev->si_tty; 2815764Sbde } 2825764Sbde return (retval); 2834Srgrimes} 2848876Srgrimes 28512675Sjulianstatic int 2864Srgrimescnclose(dev, flag, mode, p) 2874Srgrimes dev_t dev; 2884Srgrimes int flag, mode; 2894Srgrimes struct proc *p; 2904Srgrimes{ 2915764Sbde dev_t cndev; 29251654Sphk struct tty *cn_tp; 2931007Sdg 29456582Sbde if (cn_tab == NULL || cn_phys_open == NULL) 2954Srgrimes return (0); 2965764Sbde cndev = cn_tab->cn_dev; 29751654Sphk cn_tp = cndev->si_tty; 29827982Sjulian /* 29927982Sjulian * act appropriatly depending on whether it's /dev/console 30027982Sjulian * or the pysical device (e.g. /dev/sio) that's being closed. 30127982Sjulian * in either case, don't actually close the device unless 30227982Sjulian * both are closed. 30327982Sjulian */ 3045764Sbde if (dev == cndev) { 3057588Sjoerg /* the physical device is about to be closed */ 3065764Sbde cn_phys_is_open = 0; 3077588Sjoerg if (cn_is_open) { 3087588Sjoerg if (cn_tp) { 3097588Sjoerg /* perform a ttyhalfclose() */ 3107588Sjoerg /* reset session and proc group */ 3117588Sjoerg cn_tp->t_pgrp = NULL; 3127588Sjoerg cn_tp->t_session = NULL; 3137588Sjoerg } 3145764Sbde return (0); 3157588Sjoerg } 3165764Sbde } else if (major(dev) != major(cndev)) { 3177588Sjoerg /* the logical console is about to be closed */ 3185764Sbde cn_is_open = 0; 3195764Sbde if (cn_phys_is_open) 3205764Sbde return (0); 3215764Sbde dev = cndev; 3225764Sbde } 32327982Sjulian if(cn_phys_close) 32427982Sjulian return ((*cn_phys_close)(dev, flag, mode, p)); 32527982Sjulian return (0); 3264Srgrimes} 3278876Srgrimes 32812675Sjulianstatic int 3294Srgrimescnread(dev, uio, flag) 3304Srgrimes dev_t dev; 3314Srgrimes struct uio *uio; 332798Swollman int flag; 3334Srgrimes{ 33456582Sbde 33556582Sbde if (cn_tab == NULL || cn_phys_open == NULL) 3364Srgrimes return (0); 3374Srgrimes dev = cn_tab->cn_dev; 33846676Sphk return ((*devsw(dev)->d_read)(dev, uio, flag)); 3394Srgrimes} 3408876Srgrimes 34112675Sjulianstatic int 3424Srgrimescnwrite(dev, uio, flag) 3434Srgrimes dev_t dev; 3444Srgrimes struct uio *uio; 345798Swollman int flag; 3464Srgrimes{ 34756582Sbde 34856582Sbde if (cn_tab == NULL || cn_phys_open == NULL) { 34927982Sjulian uio->uio_resid = 0; /* dump the data */ 3504Srgrimes return (0); 35127982Sjulian } 3521021Sdg if (constty) 3534Srgrimes dev = constty->t_dev; 3544Srgrimes else 3554Srgrimes dev = cn_tab->cn_dev; 35646676Sphk return ((*devsw(dev)->d_write)(dev, uio, flag)); 3574Srgrimes} 3588876Srgrimes 35912675Sjulianstatic int 3604Srgrimescnioctl(dev, cmd, data, flag, p) 3614Srgrimes dev_t dev; 36236735Sdfr u_long cmd; 3634Srgrimes caddr_t data; 364798Swollman int flag; 3654Srgrimes struct proc *p; 3664Srgrimes{ 3674Srgrimes int error; 3684Srgrimes 36956582Sbde if (cn_tab == NULL || cn_phys_open == NULL) 3704Srgrimes return (0); 3714Srgrimes /* 3724Srgrimes * Superuser can always use this to wrest control of console 3734Srgrimes * output from the "virtual" console. 3744Srgrimes */ 3754Srgrimes if (cmd == TIOCCONS && constty) { 37646116Sphk error = suser(p); 3774Srgrimes if (error) 3784Srgrimes return (error); 3794Srgrimes constty = NULL; 3804Srgrimes return (0); 3814Srgrimes } 3824Srgrimes dev = cn_tab->cn_dev; 38346676Sphk return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p)); 3844Srgrimes} 3854Srgrimes 38612675Sjulianstatic int 38729368Spetercnpoll(dev, events, p) 3884Srgrimes dev_t dev; 38929368Speter int events; 3904Srgrimes struct proc *p; 3914Srgrimes{ 39218951Sjulian if ((cn_tab == NULL) || cn_mute) 3934Srgrimes return (1); 3946712Spst 3956712Spst dev = cn_tab->cn_dev; 3966712Spst 39746676Sphk return ((*devsw(dev)->d_poll)(dev, events, p)); 3984Srgrimes} 3994Srgrimes 400798Swollmanint 4014Srgrimescngetc() 4024Srgrimes{ 4035160Sjoerg int c; 40418951Sjulian if ((cn_tab == NULL) || cn_mute) 40519268Sjulian return (-1); 4065160Sjoerg c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 4075160Sjoerg if (c == '\r') c = '\n'; /* console input is always ICRNL */ 4085160Sjoerg return (c); 4094Srgrimes} 4104Srgrimes 4113728Sphkint 4123728Sphkcncheckc() 4133728Sphk{ 41418951Sjulian if ((cn_tab == NULL) || cn_mute) 41518287Sbde return (-1); 4163728Sphk return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 4173728Sphk} 4183728Sphk 419798Swollmanvoid 4204Srgrimescnputc(c) 4214Srgrimes register int c; 4224Srgrimes{ 42318951Sjulian if ((cn_tab == NULL) || cn_mute) 4244Srgrimes return; 4254Srgrimes if (c) { 4264Srgrimes if (c == '\n') 4274Srgrimes (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 4289217Sbde (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 4294Srgrimes } 4304Srgrimes} 4314Srgrimes 43255823Syokotavoid 43355823Syokotacndbctl(on) 43455823Syokota int on; 43555823Syokota{ 43655823Syokota static int refcount; 43755823Syokota 43855823Syokota if (cn_tab == NULL) 43955823Syokota return; 44055823Syokota if (!on) 44155823Syokota refcount--; 44255823Syokota if (refcount == 0 && cn_tab->cn_dbctl != NULL) 44355823Syokota (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on); 44455823Syokota if (on) 44555823Syokota refcount++; 44655823Syokota} 44755823Syokota 44812675Sjulianstatic void 44912675Sjuliancn_drvinit(void *unused) 45012517Sjulian{ 45112517Sjulian 45256525Sbde cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 45356525Sbde "console"); 45412517Sjulian} 45512517Sjulian 45612517SjulianSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 457