kern_cons.c revision 12813
1193323Sed/* 2193323Sed * Copyright (c) 1988 University of Utah. 3193323Sed * Copyright (c) 1991 The Regents of the University of California. 4193323Sed * All rights reserved. 5193323Sed * 6193323Sed * This code is derived from software contributed to Berkeley by 7193323Sed * the Systems Programming Group of the University of Utah Computer 8193323Sed * Science Department. 9193323Sed * 10193323Sed * Redistribution and use in source and binary forms, with or without 11193323Sed * modification, are permitted provided that the following conditions 12193323Sed * are met: 13193323Sed * 1. Redistributions of source code must retain the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer. 15193323Sed * 2. Redistributions in binary form must reproduce the above copyright 16193323Sed * notice, this list of conditions and the following disclaimer in the 17193323Sed * documentation and/or other materials provided with the distribution. 18193323Sed * 3. All advertising materials mentioning features or use of this software 19249423Sdim * must display the following acknowledgement: 20249423Sdim * This product includes software developed by the University of 21193323Sed * California, Berkeley and its contributors. 22193323Sed * 4. Neither the name of the University nor the names of its contributors 23198892Srdivacky * may be used to endorse or promote products derived from this software 24218893Sdim * without specific prior written permission. 25249423Sdim * 26249423Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28249423Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29249423Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36193323Sed * SUCH DAMAGE. 37193323Sed * 38193323Sed * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 39193323Sed * $Id: cons.c,v 1.39 1995/12/09 20:39:45 phk Exp $ 40193323Sed */ 41193323Sed 42193323Sed#include <sys/param.h> 43193323Sed#ifdef DEVFS 44193323Sed#include <sys/devfsext.h> 45193323Sed#endif /*DEVFS*/ 46193323Sed#include <sys/systm.h> 47193323Sed#include <sys/conf.h> 48198892Srdivacky#include <sys/kernel.h> 49193323Sed#include <sys/sysctl.h> 50193323Sed#include <sys/proc.h> 51193323Sed#include <sys/tty.h> 52212904Sdim 53193323Sed#include <machine/cpu.h> 54193323Sed#include <machine/cons.h> 55193323Sed#include <machine/stdarg.h> 56193323Sed 57212904Sdim/* XXX this should be config(8)ed. */ 58193323Sed#include "sc.h" 59212904Sdim#include "vt.h" 60212904Sdim#include "sio.h" 61193323Sedstatic struct consdev constab[] = { 62193323Sed#if NSC > 0 63193323Sed { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 64193323Sed#endif 65193323Sed#if NVT > 0 66193323Sed { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 67193323Sed#endif 68193323Sed#if NSIO > 0 69193323Sed { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 70193323Sed#endif 71193323Sed { 0 }, 72193323Sed}; 73193323Sed 74198892Srdivackystatic d_open_t cnopen; 75193323Sedstatic d_close_t cnclose; 76193323Sedstatic d_read_t cnread; 77212904Sdimstatic d_write_t cnwrite; 78193323Sedstatic d_ioctl_t cnioctl; 79193323Sedstatic d_select_t cnselect; 80193323Sed 81212904Sdim#define CDEV_MAJOR 0 82193323Sedstatic struct cdevsw cn_cdevsw = 83193323Sed { cnopen, cnclose, cnread, cnwrite, /*0*/ 84193323Sed cnioctl, nullstop, nullreset, nodevtotty,/* console */ 85212904Sdim cnselect, nommap, NULL, "console", NULL, -1 }; 86193323Sed 87193323Sedstruct tty *constty = 0; /* virtual console output device */ 88193323Sed 89212904Sdimstatic dev_t cn_dev_t; 90193323SedSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 91193323Sed &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 92193323Sed 93218893Sdimint cons_unavail = 0; /* XXX: 94218893Sdim * physical console not available for 95218893Sdim * input (i.e., it is in graphics mode) 96193323Sed */ 97193323Sed 98193323Sedstatic u_char cn_is_open; /* nonzero if logical console is open */ 99193323Sedstatic u_char cn_phys_is_open; /* nonzero if physical console is open */ 100193323Sedstatic d_close_t *cn_phys_close; /* physical device close function */ 101193323Sedstatic d_open_t *cn_phys_open; /* physical device open function */ 102193323Sedstatic struct consdev *cn_tab; /* physical console device info */ 103193323Sedstatic struct tty *cn_tp; /* physical console tty struct */ 104193323Sed#ifdef DEVFS 105193323Sedvoid *cn_devfs_token; /* represents the devfs entry */ 106193323Sed#endif /* DEVFS */ 107193323Sed 108193323Sedvoid 109193323Sedcninit() 110193323Sed{ 111193323Sed struct consdev *best_cp, *cp; 112193323Sed 113218893Sdim /* 114212904Sdim * Find the first console with the highest priority. 115218893Sdim */ 116212904Sdim best_cp = NULL; 117212904Sdim for (cp = constab; cp->cn_probe; cp++) { 118212904Sdim (*cp->cn_probe)(cp); 119193323Sed if (cp->cn_pri > CN_DEAD && 120193323Sed (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 121193323Sed best_cp = cp; 122193323Sed } 123193323Sed 124212904Sdim /* 125218893Sdim * If no console, give up. 126218893Sdim */ 127193323Sed if (best_cp == NULL) { 128193323Sed cn_tab = best_cp; 129218893Sdim return; 130193323Sed } 131218893Sdim 132193323Sed /* 133218893Sdim * Initialize console, then attach to it. This ordering allows 134218893Sdim * debugging using the previous console, if any. 135193323Sed * XXX if there was a previous console, then its driver should 136193323Sed * be informed when we forget about it. 137193323Sed */ 138193323Sed (*best_cp->cn_init)(best_cp); 139193323Sed cn_tab = best_cp; 140212904Sdim} 141218893Sdim 142218893Sdimvoid 143218893Sdimcninit_finish() 144218893Sdim{ 145218893Sdim struct cdevsw *cdp; 146218893Sdim 147218893Sdim if (cn_tab == NULL) 148218893Sdim return; 149218893Sdim 150218893Sdim /* 151218893Sdim * Hook the open and close functions. 152193323Sed */ 153193323Sed cdp = cdevsw[major(cn_tab->cn_dev)]; 154193323Sed cn_phys_close = cdp->d_close; 155193323Sed cdp->d_close = cnclose; 156218893Sdim cn_phys_open = cdp->d_open; 157193323Sed cdp->d_open = cnopen; 158202878Srdivacky cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 159202878Srdivacky cn_dev_t = cn_tp->t_dev; 160202878Srdivacky} 161202878Srdivacky 162212904Sdimstatic int 163212904Sdimcnopen(dev, flag, mode, p) 164202878Srdivacky dev_t dev; 165202878Srdivacky int flag, mode; 166202878Srdivacky struct proc *p; 167202878Srdivacky{ 168193323Sed dev_t cndev, physdev; 169193323Sed int retval; 170193323Sed 171212904Sdim if (cn_tab == NULL) 172212904Sdim return (0); 173212904Sdim cndev = cn_tab->cn_dev; 174193323Sed physdev = (major(dev) == major(cndev) ? dev : cndev); 175193323Sed retval = (*cn_phys_open)(physdev, flag, mode, p); 176193323Sed if (retval == 0) { 177193323Sed if (dev == cndev) 178193323Sed cn_phys_is_open = 1; 179193323Sed else if (physdev == cndev) 180193323Sed cn_is_open = 1; 181193323Sed } 182193323Sed return (retval); 183193323Sed} 184193323Sed 185193323Sedstatic int 186193323Sedcnclose(dev, flag, mode, p) 187193323Sed dev_t dev; 188193323Sed int flag, mode; 189218893Sdim struct proc *p; 190212904Sdim{ 191218893Sdim dev_t cndev; 192263508Sdim 193218893Sdim if (cn_tab == NULL) 194218893Sdim return (0); 195218893Sdim cndev = cn_tab->cn_dev; 196193323Sed if (dev == cndev) { 197193323Sed /* the physical device is about to be closed */ 198193323Sed cn_phys_is_open = 0; 199193323Sed if (cn_is_open) { 200193323Sed if (cn_tp) { 201193323Sed /* perform a ttyhalfclose() */ 202193323Sed /* reset session and proc group */ 203193323Sed cn_tp->t_pgrp = NULL; 204193323Sed cn_tp->t_session = NULL; 205193323Sed } 206193323Sed return (0); 207193323Sed } 208193323Sed } else if (major(dev) != major(cndev)) { 209193323Sed /* the logical console is about to be closed */ 210193323Sed cn_is_open = 0; 211193323Sed if (cn_phys_is_open) 212193323Sed return (0); 213193323Sed dev = cndev; 214193323Sed } 215193323Sed return ((*cn_phys_close)(dev, flag, mode, p)); 216193323Sed} 217193323Sed 218193323Sedstatic int 219193323Sedcnread(dev, uio, flag) 220193323Sed dev_t dev; 221193323Sed struct uio *uio; 222193323Sed int flag; 223193323Sed{ 224193323Sed if (cn_tab == NULL) 225193323Sed return (0); 226193323Sed dev = cn_tab->cn_dev; 227193323Sed return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag)); 228193323Sed} 229193323Sed 230193323Sedstatic int 231204642Srdivackycnwrite(dev, uio, flag) 232193323Sed dev_t dev; 233193323Sed struct uio *uio; 234193323Sed int flag; 235193323Sed{ 236193323Sed if (cn_tab == NULL) 237193323Sed return (0); 238193323Sed if (constty) 239193323Sed dev = constty->t_dev; 240193323Sed else 241193323Sed dev = cn_tab->cn_dev; 242193323Sed return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag)); 243193323Sed} 244193323Sed 245193323Sedstatic int 246193323Sedcnioctl(dev, cmd, data, flag, p) 247193323Sed dev_t dev; 248193323Sed int cmd; 249204642Srdivacky caddr_t data; 250193323Sed int flag; 251210299Sed struct proc *p; 252210299Sed{ 253210299Sed int error; 254193323Sed 255210299Sed if (cn_tab == NULL) 256193323Sed return (0); 257193323Sed /* 258193323Sed * Superuser can always use this to wrest control of console 259193323Sed * output from the "virtual" console. 260193323Sed */ 261210299Sed if (cmd == TIOCCONS && constty) { 262193323Sed error = suser(p->p_ucred, (u_short *) NULL); 263210299Sed if (error) 264198090Srdivacky return (error); 265198090Srdivacky constty = NULL; 266243830Sdim return (0); 267210299Sed } 268210299Sed dev = cn_tab->cn_dev; 269193323Sed return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p)); 270193323Sed} 271210299Sed 272210299Sedstatic int 273210299Sedcnselect(dev, rw, p) 274193323Sed dev_t dev; 275193323Sed int rw; 276210299Sed struct proc *p; 277210299Sed{ 278210299Sed if (cn_tab == NULL) 279193323Sed return (1); 280193323Sed 281193323Sed dev = cn_tab->cn_dev; 282193323Sed 283193323Sed return ((*cdevsw[major(dev)]->d_select)(dev, rw, p)); 284193323Sed} 285193323Sed 286210299Sedint 287193323Sedcngetc() 288193323Sed{ 289193323Sed int c; 290193323Sed if (cn_tab == NULL) 291193323Sed return (0); 292210299Sed c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 293210299Sed if (c == '\r') c = '\n'; /* console input is always ICRNL */ 294193323Sed return (c); 295193323Sed} 296193323Sed 297193323Sedint 298193323Sedcncheckc() 299193323Sed{ 300193323Sed if (cn_tab == NULL) 301193323Sed return (0); 302193323Sed return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 303193323Sed} 304193323Sed 305193323Sedvoid 306193323Sedcnputc(c) 307193323Sed register int c; 308193323Sed{ 309193323Sed if (cn_tab == NULL) 310193323Sed return; 311193323Sed if (c) { 312210299Sed if (c == '\n') 313210299Sed (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 314193323Sed (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 315193323Sed } 316193323Sed} 317193323Sed 318193323Sedint 319193323Sedpg(const char *p, ...) { 320193323Sed va_list args; 321210299Sed va_start(args, p); 322193323Sed printf("%r\n>", p, args); 323193323Sed return(cngetc()); 324193323Sed} 325193323Sed 326193323Sedstatic cn_devsw_installed = 0; 327193323Sed 328193323Sedstatic void 329193323Sedcn_drvinit(void *unused) 330218893Sdim{ 331193323Sed dev_t dev; 332243830Sdim 333193323Sed if( ! cn_devsw_installed ) { 334193323Sed dev = makedev(CDEV_MAJOR,0); 335193323Sed cdevsw_add(&dev,&cn_cdevsw,NULL); 336193323Sed cn_devsw_installed = 1; 337193323Sed#ifdef DEVFS 338193323Sed cn_devfs_token = devfs_add_devsw( 339193323Sed "/", 340193323Sed "console", 341193323Sed &cn_cdevsw, 342193323Sed 0, 343193323Sed DV_CHR, 344193323Sed 0, 345193323Sed 0, 346193323Sed 0640); 347193323Sed#endif 348193323Sed } 349193323Sed} 350193323Sed 351193323SedSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 352193323Sed 353193323Sed 354193323Sed