kern_cons.c revision 46116
1/* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 39 * $Id: cons.c,v 1.62 1999/04/27 11:14:29 phk Exp $ 40 */ 41 42#include "opt_devfs.h" 43 44#include <sys/param.h> 45#ifdef DEVFS 46#include <sys/devfsext.h> 47#endif /*DEVFS*/ 48#include <sys/systm.h> 49#include <sys/conf.h> 50#include <sys/kernel.h> 51#include <sys/reboot.h> 52#include <sys/sysctl.h> 53#include <sys/proc.h> 54#include <sys/tty.h> 55#include <sys/uio.h> 56 57#include <machine/cpu.h> 58#include <machine/cons.h> 59 60static d_open_t cnopen; 61static d_close_t cnclose; 62static d_read_t cnread; 63static d_write_t cnwrite; 64static d_ioctl_t cnioctl; 65static d_poll_t cnpoll; 66 67#define CDEV_MAJOR 0 68static struct cdevsw cn_cdevsw = { 69 cnopen, cnclose, cnread, cnwrite, 70 cnioctl, nullstop, nullreset, nodevtotty, 71 cnpoll, nommap, NULL, "console", 72 NULL, -1, nodump, nopsize, 73 D_TTY, 74}; 75 76static dev_t cn_dev_t; /* seems to be never really used */ 77SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 78 &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 79 80static int cn_mute; 81 82int cons_unavail = 0; /* XXX: 83 * physical console not available for 84 * input (i.e., it is in graphics mode) 85 */ 86 87static u_char cn_is_open; /* nonzero if logical console is open */ 88static int openmode, openflag; /* how /dev/console was openned */ 89static u_char cn_phys_is_open; /* nonzero if physical device is open */ 90static d_close_t *cn_phys_close; /* physical device close function */ 91static d_open_t *cn_phys_open; /* physical device open function */ 92static struct consdev *cn_tab; /* physical console device info */ 93static struct tty *cn_tp; /* physical console tty struct */ 94#ifdef DEVFS 95static void *cn_devfs_token; /* represents the devfs entry */ 96#endif /* DEVFS */ 97 98CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL); 99 100void 101cninit() 102{ 103 struct consdev *best_cp, *cp; 104 struct consdev **list; 105 106 /* 107 * Find the first console with the highest priority. 108 */ 109 best_cp = NULL; 110 list = (struct consdev **)cons_set.ls_items; 111 while ((cp = *list++) != NULL) { 112 if (cp->cn_probe == NULL) 113 continue; 114 (*cp->cn_probe)(cp); 115 if (cp->cn_pri > CN_DEAD && 116 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 117 best_cp = cp; 118 } 119 120 /* 121 * Check if we should mute the console (for security reasons perhaps) 122 * It can be changes dynamically using sysctl kern.consmute 123 * once we are up and going. 124 * 125 */ 126 cn_mute = ((boothowto & (RB_MUTE 127 |RB_SINGLE 128 |RB_VERBOSE 129 |RB_ASKNAME 130 |RB_CONFIG)) == RB_MUTE); 131 132 /* 133 * If no console, give up. 134 */ 135 if (best_cp == NULL) { 136 cn_tab = best_cp; 137 return; 138 } 139 140 /* 141 * Initialize console, then attach to it. This ordering allows 142 * debugging using the previous console, if any. 143 * XXX if there was a previous console, then its driver should 144 * be informed when we forget about it. 145 */ 146 (*best_cp->cn_init)(best_cp); 147 cn_tab = best_cp; 148} 149 150void 151cninit_finish() 152{ 153 struct cdevsw *cdp; 154 155 if ((cn_tab == NULL) || cn_mute) 156 return; 157 158 /* 159 * Hook the open and close functions. 160 */ 161 cdp = cdevsw[major(cn_tab->cn_dev)]; 162 cn_phys_close = cdp->d_close; 163 cdp->d_close = cnclose; 164 cn_phys_open = cdp->d_open; 165 cdp->d_open = cnopen; 166 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 167 cn_dev_t = cn_tp->t_dev; 168} 169 170static void 171cnuninit(void) 172{ 173 struct cdevsw *cdp; 174 175 if (cn_tab == NULL) 176 return; 177 178 /* 179 * Unhook the open and close functions. 180 */ 181 cdp = cdevsw[major(cn_tab->cn_dev)]; 182 cdp->d_close = cn_phys_close; 183 cn_phys_close = NULL; 184 cdp->d_open = cn_phys_open; 185 cn_phys_open = NULL; 186 cn_tp = NULL; 187 cn_dev_t = 0; 188} 189 190/* 191 * User has changed the state of the console muting. 192 * This may require us to open or close the device in question. 193 */ 194static int 195sysctl_kern_consmute SYSCTL_HANDLER_ARGS 196{ 197 int error; 198 int ocn_mute; 199 200 ocn_mute = cn_mute; 201 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 202 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { 203 if(ocn_mute && !cn_mute) { 204 /* 205 * going from muted to unmuted.. open the physical dev 206 * if the console has been openned 207 */ 208 cninit_finish(); 209 if(cn_is_open) 210 /* XXX curproc is not what we want really */ 211 error = cnopen(cn_dev_t, openflag, 212 openmode, curproc); 213 /* if it failed, back it out */ 214 if ( error != 0) cnuninit(); 215 } else if (!ocn_mute && cn_mute) { 216 /* 217 * going from unmuted to muted.. close the physical dev 218 * if it's only open via /dev/console 219 */ 220 if(cn_is_open) 221 error = cnclose(cn_dev_t, openflag, 222 openmode, curproc); 223 if ( error == 0) cnuninit(); 224 } 225 if (error != 0) { 226 /* 227 * back out the change if there was an error 228 */ 229 cn_mute = ocn_mute; 230 } 231 } 232 return (error); 233} 234 235SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 236 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); 237 238static int 239cnopen(dev, flag, mode, p) 240 dev_t dev; 241 int flag, mode; 242 struct proc *p; 243{ 244 dev_t cndev, physdev; 245 int retval = 0; 246 247 if (cn_tab == NULL) 248 return (0); 249 cndev = cn_tab->cn_dev; 250 physdev = (major(dev) == major(cndev) ? dev : cndev); 251 /* 252 * If mute is active, then non console opens don't get here 253 * so we don't need to check for that. They 254 * bypass this and go straight to the device. 255 */ 256 if(!cn_mute) 257 retval = (*cn_phys_open)(physdev, flag, mode, p); 258 if (retval == 0) { 259 /* 260 * check if we openned it via /dev/console or 261 * via the physical entry (e.g. /dev/sio0). 262 */ 263 if (dev == cndev) 264 cn_phys_is_open = 1; 265 else if (physdev == cndev) { 266 openmode = mode; 267 openflag = flag; 268 cn_is_open = 1; 269 } 270 } 271 return (retval); 272} 273 274static int 275cnclose(dev, flag, mode, p) 276 dev_t dev; 277 int flag, mode; 278 struct proc *p; 279{ 280 dev_t cndev; 281 282 if (cn_tab == NULL) 283 return (0); 284 cndev = cn_tab->cn_dev; 285 /* 286 * act appropriatly depending on whether it's /dev/console 287 * or the pysical device (e.g. /dev/sio) that's being closed. 288 * in either case, don't actually close the device unless 289 * both are closed. 290 */ 291 if (dev == cndev) { 292 /* the physical device is about to be closed */ 293 cn_phys_is_open = 0; 294 if (cn_is_open) { 295 if (cn_tp) { 296 /* perform a ttyhalfclose() */ 297 /* reset session and proc group */ 298 cn_tp->t_pgrp = NULL; 299 cn_tp->t_session = NULL; 300 } 301 return (0); 302 } 303 } else if (major(dev) != major(cndev)) { 304 /* the logical console is about to be closed */ 305 cn_is_open = 0; 306 if (cn_phys_is_open) 307 return (0); 308 dev = cndev; 309 } 310 if(cn_phys_close) 311 return ((*cn_phys_close)(dev, flag, mode, p)); 312 return (0); 313} 314 315static int 316cnread(dev, uio, flag) 317 dev_t dev; 318 struct uio *uio; 319 int flag; 320{ 321 if ((cn_tab == NULL) || cn_mute) 322 return (0); 323 dev = cn_tab->cn_dev; 324 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag)); 325} 326 327static int 328cnwrite(dev, uio, flag) 329 dev_t dev; 330 struct uio *uio; 331 int flag; 332{ 333 if ((cn_tab == NULL) || cn_mute) { 334 uio->uio_resid = 0; /* dump the data */ 335 return (0); 336 } 337 if (constty) 338 dev = constty->t_dev; 339 else 340 dev = cn_tab->cn_dev; 341 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag)); 342} 343 344static int 345cnioctl(dev, cmd, data, flag, p) 346 dev_t dev; 347 u_long cmd; 348 caddr_t data; 349 int flag; 350 struct proc *p; 351{ 352 int error; 353 354 if ((cn_tab == NULL) || cn_mute) 355 return (0); 356 /* 357 * Superuser can always use this to wrest control of console 358 * output from the "virtual" console. 359 */ 360 if (cmd == TIOCCONS && constty) { 361 error = suser(p); 362 if (error) 363 return (error); 364 constty = NULL; 365 return (0); 366 } 367 dev = cn_tab->cn_dev; 368 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p)); 369} 370 371static int 372cnpoll(dev, events, p) 373 dev_t dev; 374 int events; 375 struct proc *p; 376{ 377 if ((cn_tab == NULL) || cn_mute) 378 return (1); 379 380 dev = cn_tab->cn_dev; 381 382 return ((*cdevsw[major(dev)]->d_poll)(dev, events, p)); 383} 384 385int 386cngetc() 387{ 388 int c; 389 if ((cn_tab == NULL) || cn_mute) 390 return (-1); 391 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 392 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 393 return (c); 394} 395 396int 397cncheckc() 398{ 399 if ((cn_tab == NULL) || cn_mute) 400 return (-1); 401 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 402} 403 404void 405cnputc(c) 406 register int c; 407{ 408 if ((cn_tab == NULL) || cn_mute) 409 return; 410 if (c) { 411 if (c == '\n') 412 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 413 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 414 } 415} 416 417static cn_devsw_installed = 0; 418 419static void 420cn_drvinit(void *unused) 421{ 422 dev_t dev; 423 424 if( ! cn_devsw_installed ) { 425 dev = makedev(CDEV_MAJOR,0); 426 cdevsw_add(&dev,&cn_cdevsw,NULL); 427 cn_devsw_installed = 1; 428#ifdef DEVFS 429 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR, 430 UID_ROOT, GID_WHEEL, 0600, 431 "console"); 432#endif 433 } 434} 435 436SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 437 438 439