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