kern_cons.c revision 12701
118334Speter/* 290075Sobrien * Copyright (c) 1988 University of Utah. 3169689Skan * Copyright (c) 1991 The Regents of the University of California. 418334Speter * All rights reserved. 590075Sobrien * 618334Speter * This code is derived from software contributed to Berkeley by 790075Sobrien * the Systems Programming Group of the University of Utah Computer 890075Sobrien * Science Department. 990075Sobrien * 1090075Sobrien * Redistribution and use in source and binary forms, with or without 1118334Speter * modification, are permitted provided that the following conditions 1290075Sobrien * are met: 1390075Sobrien * 1. Redistributions of source code must retain the above copyright 1490075Sobrien * notice, this list of conditions and the following disclaimer. 1590075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1618334Speter * notice, this list of conditions and the following disclaimer in the 1718334Speter * documentation and/or other materials provided with the distribution. 1890075Sobrien * 3. All advertising materials mentioning features or use of this software 19169689Skan * must display the following acknowledgement: 20169689Skan * This product includes software developed by the University of 2118334Speter * California, Berkeley and its contributors. 22132718Skan * 4. Neither the name of the University nor the names of its contributors 23132718Skan * may be used to endorse or promote products derived from this software 24132718Skan * without specific prior written permission. 25169689Skan * 26169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28117395Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2918334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3018334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3118334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3218334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3318334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3418334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3518334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3618334Speter * SUCH DAMAGE. 3718334Speter * 3818334Speter * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 3918334Speter * $Id: cons.c,v 1.38 1995/12/08 23:20:00 phk Exp $ 4018334Speter */ 41117395Skan 4218334Speter#include <sys/param.h> 4318334Speter#ifdef DEVFS 44117395Skan#include <sys/devfsext.h> 45117395Skan#endif /*DEVFS*/ 4618334Speter#include <sys/systm.h> 4718334Speter#include <sys/conf.h> 4818334Speter#include <sys/kernel.h> 4918334Speter#include <sys/sysctl.h> 5018334Speter#include <sys/proc.h> 5118334Speter#include <sys/tty.h> 5218334Speter 5318334Speter#include <machine/cpu.h> 5418334Speter#include <machine/cons.h> 5518334Speter#include <machine/stdarg.h> 5618334Speter 5718334Speter/* XXX this should be config(8)ed. */ 5818334Speter#include "sc.h" 59117395Skan#include "vt.h" 6090075Sobrien#include "sio.h" 6190075Sobrienstatic struct consdev constab[] = { 6290075Sobrien#if NSC > 0 6390075Sobrien { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 6490075Sobrien#endif 6590075Sobrien#if NVT > 0 6690075Sobrien { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 6790075Sobrien#endif 6890075Sobrien#if NSIO > 0 6990075Sobrien { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 70132718Skan#endif 71169689Skan { 0 }, 72169689Skan}; 7390075Sobrien 7490075Sobrienstatic d_open_t cnopen; 7590075Sobrienstatic d_close_t cnclose; 7690075Sobrienstatic d_read_t cnread; 7790075Sobrienstatic d_write_t cnwrite; 7890075Sobrienstatic d_ioctl_t cnioctl; 7990075Sobrienstatic d_select_t cnselect; 8090075Sobrien 8190075Sobrien#define CDEV_MAJOR 0 8290075Sobrienstatic struct cdevsw cn_cdevsw = 8390075Sobrien { cnopen, cnclose, cnread, cnwrite, /*0*/ 8490075Sobrien cnioctl, nullstop, nullreset, nodevtotty,/* console */ 8590075Sobrien cnselect, nommap, NULL, "console", NULL, -1 }; 86132718Skan 8790075Sobrienstruct tty *constty = 0; /* virtual console output device */ 88132718Skan 8990075Sobrienstatic dev_t cn_dev_t; 9090075SobrienSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 9190075Sobrien &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 9290075Sobrien 9390075Sobrienint cons_unavail = 0; /* XXX: 9490075Sobrien * physical console not available for 9590075Sobrien * input (i.e., it is in graphics mode) 9690075Sobrien */ 9790075Sobrien 9890075Sobrienstatic u_char cn_is_open; /* nonzero if logical console is open */ 99132718Skanstatic u_char cn_phys_is_open; /* nonzero if physical console is open */ 100117395Skanstatic d_close_t *cn_phys_close; /* physical device close function */ 10190075Sobrienstatic d_open_t *cn_phys_open; /* physical device open function */ 10290075Sobrienstatic struct consdev *cn_tab; /* physical console device info */ 103169689Skanstatic struct tty *cn_tp; /* physical console tty struct */ 104132718Skan#ifdef DEVFS 10590075Sobrienvoid *cn_devfs_token; /* represents the devfs entry */ 10690075Sobrien#endif /* DEVFS */ 10790075Sobrien 10890075Sobrienvoid 10990075Sobriencninit() 11090075Sobrien{ 11190075Sobrien struct consdev *best_cp, *cp; 11290075Sobrien 11390075Sobrien /* 114117395Skan * Find the first console with the highest priority. 11590075Sobrien */ 11690075Sobrien best_cp = NULL; 11790075Sobrien for (cp = constab; cp->cn_probe; cp++) { 11890075Sobrien (*cp->cn_probe)(cp); 11990075Sobrien if (cp->cn_pri > CN_DEAD && 12090075Sobrien (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 12190075Sobrien best_cp = cp; 12290075Sobrien } 12390075Sobrien 12490075Sobrien /* 12590075Sobrien * If no console, give up. 12690075Sobrien */ 12790075Sobrien if (best_cp == NULL) { 12890075Sobrien cn_tab = best_cp; 12990075Sobrien return; 13090075Sobrien } 131117395Skan 13290075Sobrien /* 13390075Sobrien * Initialize console, then attach to it. This ordering allows 13490075Sobrien * debugging using the previous console, if any. 13590075Sobrien * XXX if there was a previous console, then its driver should 13690075Sobrien * be informed when we forget about it. 13790075Sobrien */ 138117395Skan (*best_cp->cn_init)(best_cp); 13990075Sobrien cn_tab = best_cp; 14090075Sobrien} 14190075Sobrien 14290075Sobrienvoid 14390075Sobriencninit_finish() 14490075Sobrien{ 14590075Sobrien struct cdevsw *cdp; 14690075Sobrien 14790075Sobrien if (cn_tab == NULL) 14890075Sobrien return; 14990075Sobrien 15090075Sobrien /* 15190075Sobrien * Hook the open and close functions. 15290075Sobrien */ 15390075Sobrien cdp = &cdevsw[major(cn_tab->cn_dev)]; 15490075Sobrien cn_phys_close = cdp->d_close; 15590075Sobrien cdp->d_close = cnclose; 15690075Sobrien cn_phys_open = cdp->d_open; 15790075Sobrien cdp->d_open = cnopen; 15890075Sobrien cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 15990075Sobrien cn_dev_t = cn_tp->t_dev; 16090075Sobrien} 16190075Sobrien 162169689Skanstatic int 163169689Skancnopen(dev, flag, mode, p) 164169689Skan dev_t dev; 165169689Skan int flag, mode; 166169689Skan struct proc *p; 167169689Skan{ 168169689Skan dev_t cndev, physdev; 169169689Skan int retval; 170169689Skan 171169689Skan if (cn_tab == NULL) 172169689Skan return (0); 173169689Skan cndev = cn_tab->cn_dev; 174169689Skan physdev = (major(dev) == major(cndev) ? dev : cndev); 175169689Skan retval = (*cn_phys_open)(physdev, flag, mode, p); 176169689Skan if (retval == 0) { 177169689Skan if (dev == cndev) 178169689Skan cn_phys_is_open = 1; 17918334Speter else if (physdev == cndev) 18018334Speter cn_is_open = 1; 18118334Speter } 182117395Skan return (retval); 18318334Speter} 18490075Sobrien 18590075Sobrienstatic int 18690075Sobriencnclose(dev, flag, mode, p) 18790075Sobrien dev_t dev; 18818334Speter int flag, mode; 189169689Skan struct proc *p; 190169689Skan{ 191169689Skan dev_t cndev; 19218334Speter 19390075Sobrien if (cn_tab == NULL) 19490075Sobrien return (0); 19518334Speter cndev = cn_tab->cn_dev; 19690075Sobrien if (dev == cndev) { 19790075Sobrien /* the physical device is about to be closed */ 19890075Sobrien cn_phys_is_open = 0; 19990075Sobrien if (cn_is_open) { 20090075Sobrien if (cn_tp) { 20190075Sobrien /* perform a ttyhalfclose() */ 20290075Sobrien /* reset session and proc group */ 20318334Speter cn_tp->t_pgrp = NULL; 20490075Sobrien cn_tp->t_session = NULL; 20590075Sobrien } 20690075Sobrien return (0); 20790075Sobrien } 20818334Speter } else if (major(dev) != major(cndev)) { 20990075Sobrien /* the logical console is about to be closed */ 21090075Sobrien cn_is_open = 0; 21190075Sobrien if (cn_phys_is_open) 21290075Sobrien return (0); 21318334Speter dev = cndev; 21490075Sobrien } 21590075Sobrien return ((*cn_phys_close)(dev, flag, mode, p)); 21690075Sobrien} 21790075Sobrien 21890075Sobrienstatic int 21990075Sobriencnread(dev, uio, flag) 22090075Sobrien dev_t dev; 22118334Speter struct uio *uio; 22290075Sobrien int flag; 22390075Sobrien{ 22490075Sobrien if (cn_tab == NULL) 22590075Sobrien return (0); 22690075Sobrien dev = cn_tab->cn_dev; 227117395Skan return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); 22890075Sobrien} 22990075Sobrien 23090075Sobrienstatic int 23118334Spetercnwrite(dev, uio, flag) 23290075Sobrien dev_t dev; 23390075Sobrien struct uio *uio; 23418334Speter int flag; 23518334Speter{ 23690075Sobrien if (cn_tab == NULL) 23790075Sobrien return (0); 23890075Sobrien if (constty) 23950397Sobrien dev = constty->t_dev; 24090075Sobrien else 24190075Sobrien dev = cn_tab->cn_dev; 24290075Sobrien return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); 24318334Speter} 24490075Sobrien 24590075Sobrienstatic int 24690075Sobriencnioctl(dev, cmd, data, flag, p) 24790075Sobrien dev_t dev; 24890075Sobrien int cmd; 249132718Skan caddr_t data; 250132718Skan int flag; 251132718Skan struct proc *p; 252132718Skan{ 253132718Skan int error; 25490075Sobrien 25590075Sobrien if (cn_tab == NULL) 25690075Sobrien return (0); 25790075Sobrien /* 25890075Sobrien * Superuser can always use this to wrest control of console 259169689Skan * output from the "virtual" console. 26090075Sobrien */ 26190075Sobrien if (cmd == TIOCCONS && constty) { 26290075Sobrien error = suser(p->p_ucred, (u_short *) NULL); 26390075Sobrien if (error) 26490075Sobrien return (error); 26590075Sobrien constty = NULL; 26690075Sobrien return (0); 267261188Spfg } 268261188Spfg dev = cn_tab->cn_dev; 269261188Spfg return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); 270261188Spfg} 271261188Spfg 272261188Spfgstatic int 27390075Sobriencnselect(dev, rw, p) 27490075Sobrien dev_t dev; 27590075Sobrien int rw; 27690075Sobrien struct proc *p; 27790075Sobrien{ 278169689Skan if (cn_tab == NULL) 279169689Skan return (1); 280169689Skan 28190075Sobrien dev = cn_tab->cn_dev; 282169689Skan 283169689Skan return ((*cdevsw[major(dev)].d_select)(dev, rw, p)); 284169689Skan} 285169689Skan 28690075Sobrienint 28790075Sobriencngetc() 28890075Sobrien{ 28990075Sobrien int c; 290169689Skan if (cn_tab == NULL) 291169689Skan return (0); 29290075Sobrien c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 293169689Skan if (c == '\r') c = '\n'; /* console input is always ICRNL */ 294169689Skan return (c); 29590075Sobrien} 296169689Skan 297169689Skanint 298169689Skancncheckc() 29990075Sobrien{ 30090075Sobrien if (cn_tab == NULL) 30190075Sobrien return (0); 30290075Sobrien return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 30390075Sobrien} 30490075Sobrien 30518334Spetervoid 306117395Skancnputc(c) 307117395Skan register int c; 30896263Sobrien{ 309169689Skan if (cn_tab == NULL) 310169689Skan return; 311169689Skan if (c) { 312169689Skan if (c == '\n') 313169689Skan (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 314169689Skan (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 315169689Skan } 31618334Speter} 31790075Sobrien 31818334Speterint 319169689Skanpg(const char *p, ...) { 320169689Skan va_list args; 32190075Sobrien va_start(args, p); 322169689Skan printf("%r\n>", p, args); 323169689Skan return(cngetc()); 32490075Sobrien} 325169689Skan 32618334Speterstatic cn_devsw_installed = 0; 32790075Sobrien 328117395Skanstatic void 32990075Sobriencn_drvinit(void *unused) 330169689Skan{ 331169689Skan dev_t dev; 332169689Skan 33318334Speter if( ! cn_devsw_installed ) { 33490075Sobrien dev = makedev(CDEV_MAJOR,0); 33590075Sobrien cdevsw_add(&dev,&cn_cdevsw,NULL); 33690075Sobrien cn_devsw_installed = 1; 33718334Speter#ifdef DEVFS 33818334Speter cn_devfs_token = devfs_add_devsw( 339132718Skan "/", 340132718Skan "console", 341132718Skan &cn_cdevsw, 342132718Skan 0, 343169689Skan DV_CHR, 344169689Skan 0, 345169689Skan 0, 346169689Skan 0640); 347169689Skan#endif 348169689Skan } 349169689Skan} 350169689Skan 351169689SkanSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 352169689Skan 353169689Skan 354169689Skan