kern_cons.c revision 27129
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.51 1997/02/22 09:32:10 peter Exp $ 40 */ 41 42#include <sys/param.h> 43#ifdef DEVFS 44#include <sys/devfsext.h> 45#endif /*DEVFS*/ 46#include <sys/systm.h> 47#include <sys/conf.h> 48#include <sys/kernel.h> 49#include <sys/reboot.h> 50#include <sys/sysctl.h> 51#include <sys/proc.h> 52#include <sys/tty.h> 53 54#include <machine/cpu.h> 55#include <machine/cons.h> 56 57/* XXX this should be config(8)ed. */ 58#include "sc.h" 59#include "vt.h" 60#include "sio.h" 61static struct consdev constab[] = { 62#if NSC > 0 63 { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 64#endif 65#if NVT > 0 66 { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 67#endif 68#if NSIO > 0 69 { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 70#endif 71 { 0 }, 72}; 73 74static d_open_t cnopen; 75static d_close_t cnclose; 76static d_read_t cnread; 77static d_write_t cnwrite; 78static d_ioctl_t cnioctl; 79static d_select_t cnselect; 80 81#define CDEV_MAJOR 0 82static struct cdevsw cn_cdevsw = 83 { cnopen, cnclose, cnread, cnwrite, /*0*/ 84 cnioctl, nullstop, nullreset, nodevtotty,/* console */ 85 cnselect, nommap, NULL, "console", NULL, -1 }; 86 87static dev_t cn_dev_t; 88SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 89 &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 90static int cn_mute; 91SYSCTL_INT(_kern, OID_AUTO, consmute, CTLFLAG_RW, &cn_mute, 0, ""); 92 93int cons_unavail = 0; /* XXX: 94 * physical console not available for 95 * input (i.e., it is in graphics mode) 96 */ 97 98static u_char cn_is_open; /* nonzero if logical console is open */ 99static u_char cn_phys_is_open; /* nonzero if physical console is open */ 100static d_close_t *cn_phys_close; /* physical device close function */ 101static d_open_t *cn_phys_open; /* physical device open function */ 102static struct consdev *cn_tab; /* physical console device info */ 103static struct tty *cn_tp; /* physical console tty struct */ 104#ifdef DEVFS 105void *cn_devfs_token; /* represents the devfs entry */ 106#endif /* DEVFS */ 107 108void 109cninit() 110{ 111 struct consdev *best_cp, *cp; 112 113 /* 114 * Find the first console with the highest priority. 115 */ 116 best_cp = NULL; 117 for (cp = constab; cp->cn_probe; cp++) { 118 (*cp->cn_probe)(cp); 119 if (cp->cn_pri > CN_DEAD && 120 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 121 best_cp = cp; 122 } 123 124 /* 125 * Check if we should mute the console (for security reasons perhaps) 126 * It can be changes dynamically using sysctl kern.consmute 127 * once we are up and going. 128 * 129 */ 130 cn_mute = ((boothowto & (RB_MUTE 131 |RB_SINGLE 132 |RB_VERBOSE 133 |RB_ASKNAME 134 |RB_CONFIG)) == RB_MUTE); 135 136 /* 137 * If no console, give up. 138 */ 139 if (best_cp == NULL) { 140 cn_tab = best_cp; 141 return; 142 } 143 144 /* 145 * Initialize console, then attach to it. This ordering allows 146 * debugging using the previous console, if any. 147 * XXX if there was a previous console, then its driver should 148 * be informed when we forget about it. 149 */ 150 (*best_cp->cn_init)(best_cp); 151 cn_tab = best_cp; 152} 153 154void 155cninit_finish() 156{ 157 struct cdevsw *cdp; 158 159 if (cn_tab == NULL) 160 return; 161 162 /* 163 * Hook the open and close functions. 164 */ 165 cdp = cdevsw[major(cn_tab->cn_dev)]; 166 cn_phys_close = cdp->d_close; 167 cdp->d_close = cnclose; 168 cn_phys_open = cdp->d_open; 169 cdp->d_open = cnopen; 170 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 171 cn_dev_t = cn_tp->t_dev; 172} 173 174static int 175cnopen(dev, flag, mode, p) 176 dev_t dev; 177 int flag, mode; 178 struct proc *p; 179{ 180 dev_t cndev, physdev; 181 int retval; 182 183 if (cn_tab == NULL) 184 return (0); 185 cndev = cn_tab->cn_dev; 186 physdev = (major(dev) == major(cndev) ? dev : cndev); 187 retval = (*cn_phys_open)(physdev, flag, mode, p); 188 if (retval == 0) { 189 if (dev == cndev) 190 cn_phys_is_open = 1; 191 else if (physdev == cndev) 192 cn_is_open = 1; 193 } 194 return (retval); 195} 196 197static int 198cnclose(dev, flag, mode, p) 199 dev_t dev; 200 int flag, mode; 201 struct proc *p; 202{ 203 dev_t cndev; 204 205 if (cn_tab == NULL) 206 return (0); 207 cndev = cn_tab->cn_dev; 208 if (dev == cndev) { 209 /* the physical device is about to be closed */ 210 cn_phys_is_open = 0; 211 if (cn_is_open) { 212 if (cn_tp) { 213 /* perform a ttyhalfclose() */ 214 /* reset session and proc group */ 215 cn_tp->t_pgrp = NULL; 216 cn_tp->t_session = NULL; 217 } 218 return (0); 219 } 220 } else if (major(dev) != major(cndev)) { 221 /* the logical console is about to be closed */ 222 cn_is_open = 0; 223 if (cn_phys_is_open) 224 return (0); 225 dev = cndev; 226 } 227 return ((*cn_phys_close)(dev, flag, mode, p)); 228} 229 230static int 231cnread(dev, uio, flag) 232 dev_t dev; 233 struct uio *uio; 234 int flag; 235{ 236 if ((cn_tab == NULL) || cn_mute) 237 return (0); 238 dev = cn_tab->cn_dev; 239 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag)); 240} 241 242static int 243cnwrite(dev, uio, flag) 244 dev_t dev; 245 struct uio *uio; 246 int flag; 247{ 248 if ((cn_tab == NULL) || cn_mute) 249 return (0); 250 if (constty) 251 dev = constty->t_dev; 252 else 253 dev = cn_tab->cn_dev; 254 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag)); 255} 256 257static int 258cnioctl(dev, cmd, data, flag, p) 259 dev_t dev; 260 int cmd; 261 caddr_t data; 262 int flag; 263 struct proc *p; 264{ 265 int error; 266 267 if ((cn_tab == NULL) || cn_mute) 268 return (0); 269 /* 270 * Superuser can always use this to wrest control of console 271 * output from the "virtual" console. 272 */ 273 if (cmd == TIOCCONS && constty) { 274 error = suser(p->p_ucred, (u_short *) NULL); 275 if (error) 276 return (error); 277 constty = NULL; 278 return (0); 279 } 280 dev = cn_tab->cn_dev; 281 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p)); 282} 283 284static int 285cnselect(dev, rw, p) 286 dev_t dev; 287 int rw; 288 struct proc *p; 289{ 290 if ((cn_tab == NULL) || cn_mute) 291 return (1); 292 293 dev = cn_tab->cn_dev; 294 295 return ((*cdevsw[major(dev)]->d_select)(dev, rw, p)); 296} 297 298int 299cngetc() 300{ 301 int c; 302 if ((cn_tab == NULL) || cn_mute) 303 return (-1); 304 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 305 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 306 return (c); 307} 308 309int 310cncheckc() 311{ 312 if ((cn_tab == NULL) || cn_mute) 313 return (-1); 314 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 315} 316 317void 318cnputc(c) 319 register int c; 320{ 321 if ((cn_tab == NULL) || cn_mute) 322 return; 323 if (c) { 324 if (c == '\n') 325 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 326 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 327 } 328} 329 330static cn_devsw_installed = 0; 331 332static void 333cn_drvinit(void *unused) 334{ 335 dev_t dev; 336 337 if( ! cn_devsw_installed ) { 338 dev = makedev(CDEV_MAJOR,0); 339 cdevsw_add(&dev,&cn_cdevsw,NULL); 340 cn_devsw_installed = 1; 341#ifdef DEVFS 342 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR, 343 UID_ROOT, GID_WHEEL, 0600, 344 "console"); 345#endif 346 } 347} 348 349SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 350 351 352