kern_cons.c revision 41612
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.59 1998/08/23 08:26:40 bde 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 60/* XXX this should be config(8)ed. */ 61#include "sc.h" 62#include "vt.h" 63#include "sio.h" 64static struct consdev constab[] = { 65#if NSC > 0 66 { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 67#endif 68#if NVT > 0 69 { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 70#endif 71#if NSIO > 0 72 { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 73#endif 74 { 0 }, 75}; 76 77static d_open_t cnopen; 78static d_close_t cnclose; 79static d_read_t cnread; 80static d_write_t cnwrite; 81static d_ioctl_t cnioctl; 82static d_poll_t cnpoll; 83 84#define CDEV_MAJOR 0 85static struct cdevsw cn_cdevsw = { 86 cnopen, cnclose, cnread, cnwrite, 87 cnioctl, nullstop, nullreset, nodevtotty, 88 cnpoll, nommap, NULL, "console", 89 NULL, -1, nodump, nopsize, 90 D_TTY, 91}; 92 93static dev_t cn_dev_t; /* seems to be never really used */ 94SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, 95 &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 96 97static int cn_mute; 98 99int cons_unavail = 0; /* XXX: 100 * physical console not available for 101 * input (i.e., it is in graphics mode) 102 */ 103 104static u_char cn_is_open; /* nonzero if logical console is open */ 105static int openmode, openflag; /* how /dev/console was openned */ 106static u_char cn_phys_is_open; /* nonzero if physical device is open */ 107static d_close_t *cn_phys_close; /* physical device close function */ 108static d_open_t *cn_phys_open; /* physical device open function */ 109static struct consdev *cn_tab; /* physical console device info */ 110static struct tty *cn_tp; /* physical console tty struct */ 111#ifdef DEVFS 112static void *cn_devfs_token; /* represents the devfs entry */ 113#endif /* DEVFS */ 114 115void 116cninit() 117{ 118 struct consdev *best_cp, *cp; 119 120 /* 121 * Find the first console with the highest priority. 122 */ 123 best_cp = NULL; 124 for (cp = constab; cp->cn_probe; cp++) { 125 (*cp->cn_probe)(cp); 126 if (cp->cn_pri > CN_DEAD && 127 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 128 best_cp = cp; 129 } 130 131 /* 132 * Check if we should mute the console (for security reasons perhaps) 133 * It can be changes dynamically using sysctl kern.consmute 134 * once we are up and going. 135 * 136 */ 137 cn_mute = ((boothowto & (RB_MUTE 138 |RB_SINGLE 139 |RB_VERBOSE 140 |RB_ASKNAME 141 |RB_CONFIG)) == RB_MUTE); 142 143 /* 144 * If no console, give up. 145 */ 146 if (best_cp == NULL) { 147 cn_tab = best_cp; 148 return; 149 } 150 151 /* 152 * Initialize console, then attach to it. This ordering allows 153 * debugging using the previous console, if any. 154 * XXX if there was a previous console, then its driver should 155 * be informed when we forget about it. 156 */ 157 (*best_cp->cn_init)(best_cp); 158 cn_tab = best_cp; 159} 160 161void 162cninit_finish() 163{ 164 struct cdevsw *cdp; 165 166 if ((cn_tab == NULL) || cn_mute) 167 return; 168 169 /* 170 * Hook the open and close functions. 171 */ 172 cdp = cdevsw[major(cn_tab->cn_dev)]; 173 cn_phys_close = cdp->d_close; 174 cdp->d_close = cnclose; 175 cn_phys_open = cdp->d_open; 176 cdp->d_open = cnopen; 177 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 178 cn_dev_t = cn_tp->t_dev; 179} 180 181static void 182cnuninit(void) 183{ 184 struct cdevsw *cdp; 185 186 if (cn_tab == NULL) 187 return; 188 189 /* 190 * Unhook the open and close functions. 191 */ 192 cdp = cdevsw[major(cn_tab->cn_dev)]; 193 cdp->d_close = cn_phys_close; 194 cn_phys_close = NULL; 195 cdp->d_open = cn_phys_open; 196 cn_phys_open = NULL; 197 cn_tp = NULL; 198 cn_dev_t = 0; 199} 200 201/* 202 * User has changed the state of the console muting. 203 * This may require us to open or close the device in question. 204 */ 205static int 206sysctl_kern_consmute SYSCTL_HANDLER_ARGS 207{ 208 int error; 209 int ocn_mute; 210 211 ocn_mute = cn_mute; 212 error = sysctl_handle_int(oidp, &cn_mute, 0, req); 213 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { 214 if(ocn_mute && !cn_mute) { 215 /* 216 * going from muted to unmuted.. open the physical dev 217 * if the console has been openned 218 */ 219 cninit_finish(); 220 if(cn_is_open) 221 /* XXX curproc is not what we want really */ 222 error = cnopen(cn_dev_t, openflag, 223 openmode, curproc); 224 /* if it failed, back it out */ 225 if ( error != 0) cnuninit(); 226 } else if (!ocn_mute && cn_mute) { 227 /* 228 * going from unmuted to muted.. close the physical dev 229 * if it's only open via /dev/console 230 */ 231 if(cn_is_open) 232 error = cnclose(cn_dev_t, openflag, 233 openmode, curproc); 234 if ( error == 0) cnuninit(); 235 } 236 if (error != 0) { 237 /* 238 * back out the change if there was an error 239 */ 240 cn_mute = ocn_mute; 241 } 242 } 243 return (error); 244} 245 246SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 247 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); 248 249static int 250cnopen(dev, flag, mode, p) 251 dev_t dev; 252 int flag, mode; 253 struct proc *p; 254{ 255 dev_t cndev, physdev; 256 int retval = 0; 257 258 if (cn_tab == NULL) 259 return (0); 260 cndev = cn_tab->cn_dev; 261 physdev = (major(dev) == major(cndev) ? dev : cndev); 262 /* 263 * If mute is active, then non console opens don't get here 264 * so we don't need to check for that. They 265 * bypass this and go straight to the device. 266 */ 267 if(!cn_mute) 268 retval = (*cn_phys_open)(physdev, flag, mode, p); 269 if (retval == 0) { 270 /* 271 * check if we openned it via /dev/console or 272 * via the physical entry (e.g. /dev/sio0). 273 */ 274 if (dev == cndev) 275 cn_phys_is_open = 1; 276 else if (physdev == cndev) { 277 openmode = mode; 278 openflag = flag; 279 cn_is_open = 1; 280 } 281 } 282 return (retval); 283} 284 285static int 286cnclose(dev, flag, mode, p) 287 dev_t dev; 288 int flag, mode; 289 struct proc *p; 290{ 291 dev_t cndev; 292 293 if (cn_tab == NULL) 294 return (0); 295 cndev = cn_tab->cn_dev; 296 /* 297 * act appropriatly depending on whether it's /dev/console 298 * or the pysical device (e.g. /dev/sio) that's being closed. 299 * in either case, don't actually close the device unless 300 * both are closed. 301 */ 302 if (dev == cndev) { 303 /* the physical device is about to be closed */ 304 cn_phys_is_open = 0; 305 if (cn_is_open) { 306 if (cn_tp) { 307 /* perform a ttyhalfclose() */ 308 /* reset session and proc group */ 309 cn_tp->t_pgrp = NULL; 310 cn_tp->t_session = NULL; 311 } 312 return (0); 313 } 314 } else if (major(dev) != major(cndev)) { 315 /* the logical console is about to be closed */ 316 cn_is_open = 0; 317 if (cn_phys_is_open) 318 return (0); 319 dev = cndev; 320 } 321 if(cn_phys_close) 322 return ((*cn_phys_close)(dev, flag, mode, p)); 323 return (0); 324} 325 326static int 327cnread(dev, uio, flag) 328 dev_t dev; 329 struct uio *uio; 330 int flag; 331{ 332 if ((cn_tab == NULL) || cn_mute) 333 return (0); 334 dev = cn_tab->cn_dev; 335 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag)); 336} 337 338static int 339cnwrite(dev, uio, flag) 340 dev_t dev; 341 struct uio *uio; 342 int flag; 343{ 344 if ((cn_tab == NULL) || cn_mute) { 345 uio->uio_resid = 0; /* dump the data */ 346 return (0); 347 } 348 if (constty) 349 dev = constty->t_dev; 350 else 351 dev = cn_tab->cn_dev; 352 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag)); 353} 354 355static int 356cnioctl(dev, cmd, data, flag, p) 357 dev_t dev; 358 u_long cmd; 359 caddr_t data; 360 int flag; 361 struct proc *p; 362{ 363 int error; 364 365 if ((cn_tab == NULL) || cn_mute) 366 return (0); 367 /* 368 * Superuser can always use this to wrest control of console 369 * output from the "virtual" console. 370 */ 371 if (cmd == TIOCCONS && constty) { 372 error = suser(p->p_ucred, (u_short *) NULL); 373 if (error) 374 return (error); 375 constty = NULL; 376 return (0); 377 } 378 dev = cn_tab->cn_dev; 379 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p)); 380} 381 382static int 383cnpoll(dev, events, p) 384 dev_t dev; 385 int events; 386 struct proc *p; 387{ 388 if ((cn_tab == NULL) || cn_mute) 389 return (1); 390 391 dev = cn_tab->cn_dev; 392 393 return ((*cdevsw[major(dev)]->d_poll)(dev, events, p)); 394} 395 396int 397cngetc() 398{ 399 int c; 400 if ((cn_tab == NULL) || cn_mute) 401 return (-1); 402 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 403 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 404 return (c); 405} 406 407int 408cncheckc() 409{ 410 if ((cn_tab == NULL) || cn_mute) 411 return (-1); 412 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 413} 414 415void 416cnputc(c) 417 register int c; 418{ 419 if ((cn_tab == NULL) || cn_mute) 420 return; 421 if (c) { 422 if (c == '\n') 423 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 424 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 425 } 426} 427 428static cn_devsw_installed = 0; 429 430static void 431cn_drvinit(void *unused) 432{ 433 dev_t dev; 434 435 if( ! cn_devsw_installed ) { 436 dev = makedev(CDEV_MAJOR,0); 437 cdevsw_add(&dev,&cn_cdevsw,NULL); 438 cn_devsw_installed = 1; 439#ifdef DEVFS 440 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR, 441 UID_ROOT, GID_WHEEL, 0600, 442 "console"); 443#endif 444 } 445} 446 447SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 448 449 450