kern_cons.c revision 18287
1169695Skan/* 2169695Skan * Copyright (c) 1988 University of Utah. 3169695Skan * Copyright (c) 1991 The Regents of the University of California. 4169695Skan * All rights reserved. 5169695Skan * 6169695Skan * This code is derived from software contributed to Berkeley by 7169695Skan * the Systems Programming Group of the University of Utah Computer 8169695Skan * Science Department. 9169695Skan * 10169695Skan * Redistribution and use in source and binary forms, with or without 11169695Skan * modification, are permitted provided that the following conditions 12169695Skan * are met: 13169695Skan * 1. Redistributions of source code must retain the above copyright 14169695Skan * notice, this list of conditions and the following disclaimer. 15169695Skan * 2. Redistributions in binary form must reproduce the above copyright 16169695Skan * notice, this list of conditions and the following disclaimer in the 17169695Skan * documentation and/or other materials provided with the distribution. 18169695Skan * 3. All advertising materials mentioning features or use of this software 19169695Skan * must display the following acknowledgement: 20169695Skan * This product includes software developed by the University of 21169695Skan * California, Berkeley and its contributors. 22169695Skan * 4. Neither the name of the University nor the names of its contributors 23169695Skan * may be used to endorse or promote products derived from this software 24169695Skan * without specific prior written permission. 25169695Skan * 26169695Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27169695Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28169695Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29169695Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30169695Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31169695Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32169695Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33169695Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34169695Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35169695Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36169695Skan * SUCH DAMAGE. 37169695Skan * 38169695Skan * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 39169695Skan * $Id: cons.c,v 1.46 1996/05/01 03:32:46 bde Exp $ 40169695Skan */ 41169695Skan 42169695Skan#include <sys/param.h> 43169695Skan#ifdef DEVFS 44169695Skan#include <sys/devfsext.h> 45169695Skan#endif /*DEVFS*/ 46169695Skan#include <sys/systm.h> 47169695Skan#include <sys/conf.h> 48169695Skan#include <sys/kernel.h> 49169695Skan#include <sys/sysctl.h> 50169695Skan#include <sys/proc.h> 51169695Skan#include <sys/tty.h> 52169695Skan 53169695Skan#include <machine/cpu.h> 54169695Skan#include <machine/cons.h> 55169695Skan 56169695Skan/* XXX this should be config(8)ed. */ 57169695Skan#include "sc.h" 58169695Skan#include "vt.h" 59169695Skan#include "sio.h" 60169695Skanstatic struct consdev constab[] = { 61169695Skan#if NSC > 0 62169695Skan { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 63169695Skan#endif 64169695Skan#if NVT > 0 65169695Skan { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 66169695Skan#endif 67169695Skan#if NSIO > 0 68169695Skan { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 69169695Skan#endif 70169695Skan { 0 }, 71169695Skan}; 72169695Skan 73169695Skanstatic d_open_t cnopen; 74169695Skanstatic d_close_t cnclose; 75169695Skanstatic d_read_t cnread; 76169695Skanstatic d_write_t cnwrite; 77169695Skanstatic d_ioctl_t cnioctl; 78169695Skanstatic d_select_t cnselect; 79169695Skan 80169695Skan#define CDEV_MAJOR 0 81169695Skanstatic struct cdevsw cn_cdevsw = 82169695Skan { cnopen, cnclose, cnread, cnwrite, /*0*/ 83169695Skan cnioctl, nullstop, nullreset, nodevtotty,/* console */ 84169695Skan cnselect, nommap, NULL, "console", NULL, -1 }; 85169695Skan 86169695Skanstruct tty *constty = 0; /* virtual console output device */ 87169695Skan 88169695Skanstatic dev_t cn_dev_t; 89169695SkanSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 90169695Skan &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 91169695Skan 92169695Skanint cons_unavail = 0; /* XXX: 93169695Skan * physical console not available for 94169695Skan * input (i.e., it is in graphics mode) 95169695Skan */ 96169695Skan 97169695Skanstatic u_char cn_is_open; /* nonzero if logical console is open */ 98169695Skanstatic u_char cn_phys_is_open; /* nonzero if physical console is open */ 99169695Skanstatic d_close_t *cn_phys_close; /* physical device close function */ 100169695Skanstatic d_open_t *cn_phys_open; /* physical device open function */ 101169695Skanstatic struct consdev *cn_tab; /* physical console device info */ 102169695Skanstatic struct tty *cn_tp; /* physical console tty struct */ 103169695Skan#ifdef DEVFS 104169695Skanvoid *cn_devfs_token; /* represents the devfs entry */ 105169695Skan#endif /* DEVFS */ 106169695Skan 107169695Skanvoid 108169695Skancninit() 109169695Skan{ 110169695Skan struct consdev *best_cp, *cp; 111169695Skan 112169695Skan /* 113169695Skan * Find the first console with the highest priority. 114169695Skan */ 115169695Skan best_cp = NULL; 116169695Skan for (cp = constab; cp->cn_probe; cp++) { 117169695Skan (*cp->cn_probe)(cp); 118169695Skan if (cp->cn_pri > CN_DEAD && 119169695Skan (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 120169695Skan best_cp = cp; 121169695Skan } 122169695Skan 123169695Skan /* 124169695Skan * If no console, give up. 125169695Skan */ 126169695Skan if (best_cp == NULL) { 127169695Skan cn_tab = best_cp; 128169695Skan return; 129169695Skan } 130169695Skan 131169695Skan /* 132 * Initialize console, then attach to it. This ordering allows 133 * debugging using the previous console, if any. 134 * XXX if there was a previous console, then its driver should 135 * be informed when we forget about it. 136 */ 137 (*best_cp->cn_init)(best_cp); 138 cn_tab = best_cp; 139} 140 141void 142cninit_finish() 143{ 144 struct cdevsw *cdp; 145 146 if (cn_tab == NULL) 147 return; 148 149 /* 150 * Hook the open and close functions. 151 */ 152 cdp = cdevsw[major(cn_tab->cn_dev)]; 153 cn_phys_close = cdp->d_close; 154 cdp->d_close = cnclose; 155 cn_phys_open = cdp->d_open; 156 cdp->d_open = cnopen; 157 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 158 cn_dev_t = cn_tp->t_dev; 159} 160 161static int 162cnopen(dev, flag, mode, p) 163 dev_t dev; 164 int flag, mode; 165 struct proc *p; 166{ 167 dev_t cndev, physdev; 168 int retval; 169 170 if (cn_tab == NULL) 171 return (0); 172 cndev = cn_tab->cn_dev; 173 physdev = (major(dev) == major(cndev) ? dev : cndev); 174 retval = (*cn_phys_open)(physdev, flag, mode, p); 175 if (retval == 0) { 176 if (dev == cndev) 177 cn_phys_is_open = 1; 178 else if (physdev == cndev) 179 cn_is_open = 1; 180 } 181 return (retval); 182} 183 184static int 185cnclose(dev, flag, mode, p) 186 dev_t dev; 187 int flag, mode; 188 struct proc *p; 189{ 190 dev_t cndev; 191 192 if (cn_tab == NULL) 193 return (0); 194 cndev = cn_tab->cn_dev; 195 if (dev == cndev) { 196 /* the physical device is about to be closed */ 197 cn_phys_is_open = 0; 198 if (cn_is_open) { 199 if (cn_tp) { 200 /* perform a ttyhalfclose() */ 201 /* reset session and proc group */ 202 cn_tp->t_pgrp = NULL; 203 cn_tp->t_session = NULL; 204 } 205 return (0); 206 } 207 } else if (major(dev) != major(cndev)) { 208 /* the logical console is about to be closed */ 209 cn_is_open = 0; 210 if (cn_phys_is_open) 211 return (0); 212 dev = cndev; 213 } 214 return ((*cn_phys_close)(dev, flag, mode, p)); 215} 216 217static int 218cnread(dev, uio, flag) 219 dev_t dev; 220 struct uio *uio; 221 int flag; 222{ 223 if (cn_tab == NULL) 224 return (0); 225 dev = cn_tab->cn_dev; 226 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag)); 227} 228 229static int 230cnwrite(dev, uio, flag) 231 dev_t dev; 232 struct uio *uio; 233 int flag; 234{ 235 if (cn_tab == NULL) 236 return (0); 237 if (constty) 238 dev = constty->t_dev; 239 else 240 dev = cn_tab->cn_dev; 241 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag)); 242} 243 244static int 245cnioctl(dev, cmd, data, flag, p) 246 dev_t dev; 247 int cmd; 248 caddr_t data; 249 int flag; 250 struct proc *p; 251{ 252 int error; 253 254 if (cn_tab == NULL) 255 return (0); 256 /* 257 * Superuser can always use this to wrest control of console 258 * output from the "virtual" console. 259 */ 260 if (cmd == TIOCCONS && constty) { 261 error = suser(p->p_ucred, (u_short *) NULL); 262 if (error) 263 return (error); 264 constty = NULL; 265 return (0); 266 } 267 dev = cn_tab->cn_dev; 268 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p)); 269} 270 271static int 272cnselect(dev, rw, p) 273 dev_t dev; 274 int rw; 275 struct proc *p; 276{ 277 if (cn_tab == NULL) 278 return (1); 279 280 dev = cn_tab->cn_dev; 281 282 return ((*cdevsw[major(dev)]->d_select)(dev, rw, p)); 283} 284 285int 286cngetc() 287{ 288 int c; 289 if (cn_tab == NULL) 290 return (0); 291 c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 292 if (c == '\r') c = '\n'; /* console input is always ICRNL */ 293 return (c); 294} 295 296int 297cncheckc() 298{ 299 if (cn_tab == NULL) 300 return (-1); 301 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 302} 303 304void 305cnputc(c) 306 register int c; 307{ 308 if (cn_tab == NULL) 309 return; 310 if (c) { 311 if (c == '\n') 312 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 313 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 314 } 315} 316 317static cn_devsw_installed = 0; 318 319static void 320cn_drvinit(void *unused) 321{ 322 dev_t dev; 323 324 if( ! cn_devsw_installed ) { 325 dev = makedev(CDEV_MAJOR,0); 326 cdevsw_add(&dev,&cn_cdevsw,NULL); 327 cn_devsw_installed = 1; 328#ifdef DEVFS 329 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR, 330 UID_ROOT, GID_WHEEL, 0600, 331 "console"); 332#endif 333 } 334} 335 336SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 337 338 339