kern_cons.c revision 12701
14Srgrimes/* 24Srgrimes * Copyright (c) 1988 University of Utah. 34Srgrimes * Copyright (c) 1991 The Regents of the University of California. 44Srgrimes * All rights reserved. 54Srgrimes * 64Srgrimes * This code is derived from software contributed to Berkeley by 74Srgrimes * the Systems Programming Group of the University of Utah Computer 84Srgrimes * Science Department. 94Srgrimes * 104Srgrimes * Redistribution and use in source and binary forms, with or without 114Srgrimes * modification, are permitted provided that the following conditions 124Srgrimes * are met: 134Srgrimes * 1. Redistributions of source code must retain the above copyright 144Srgrimes * notice, this list of conditions and the following disclaimer. 154Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 164Srgrimes * notice, this list of conditions and the following disclaimer in the 174Srgrimes * documentation and/or other materials provided with the distribution. 184Srgrimes * 3. All advertising materials mentioning features or use of this software 194Srgrimes * must display the following acknowledgement: 204Srgrimes * This product includes software developed by the University of 214Srgrimes * California, Berkeley and its contributors. 224Srgrimes * 4. Neither the name of the University nor the names of its contributors 234Srgrimes * may be used to endorse or promote products derived from this software 244Srgrimes * without specific prior written permission. 254Srgrimes * 264Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 274Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 284Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 294Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 304Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 314Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 324Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 334Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 344Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 354Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 364Srgrimes * SUCH DAMAGE. 374Srgrimes * 38620Srgrimes * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 3912701Sphk * $Id: cons.c,v 1.38 1995/12/08 23:20:00 phk Exp $ 404Srgrimes */ 414Srgrimes 422056Swollman#include <sys/param.h> 4312675Sjulian#ifdef DEVFS 4412675Sjulian#include <sys/devfsext.h> 4512675Sjulian#endif /*DEVFS*/ 461549Srgrimes#include <sys/systm.h> 475764Sbde#include <sys/conf.h> 4812675Sjulian#include <sys/kernel.h> 4912701Sphk#include <sys/sysctl.h> 502056Swollman#include <sys/proc.h> 512056Swollman#include <sys/tty.h> 524Srgrimes 5312701Sphk#include <machine/cpu.h> 542056Swollman#include <machine/cons.h> 555764Sbde#include <machine/stdarg.h> 564Srgrimes 578023Sbde/* XXX this should be config(8)ed. */ 588047Sbde#include "sc.h" 598047Sbde#include "vt.h" 608047Sbde#include "sio.h" 615764Sbdestatic struct consdev constab[] = { 6210666Sbde#if NSC > 0 6310666Sbde { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 6410666Sbde#endif 6510666Sbde#if NVT > 0 663728Sphk { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 672423Sdg#endif 68849Sdg#if NSIO > 0 693728Sphk { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 70849Sdg#endif 714Srgrimes { 0 }, 724Srgrimes}; 734Srgrimes 7412675Sjulianstatic d_open_t cnopen; 7512675Sjulianstatic d_close_t cnclose; 7612675Sjulianstatic d_read_t cnread; 7712675Sjulianstatic d_write_t cnwrite; 7812675Sjulianstatic d_ioctl_t cnioctl; 7912675Sjulianstatic d_select_t cnselect; 8012675Sjulian 8112675Sjulian#define CDEV_MAJOR 0 8212678Sphkstatic struct cdevsw cn_cdevsw = 8312675Sjulian { cnopen, cnclose, cnread, cnwrite, /*0*/ 8412675Sjulian cnioctl, nullstop, nullreset, nodevtotty,/* console */ 8512675Sjulian cnselect, nommap, NULL, "console", NULL, -1 }; 8612675Sjulian 874Srgrimesstruct tty *constty = 0; /* virtual console output device */ 8812701Sphk 8912701Sphkstatic dev_t cn_dev_t; 9012701SphkSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 9112701Sphk &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 9212701Sphk 937680Sjoergint cons_unavail = 0; /* XXX: 947680Sjoerg * physical console not available for 957680Sjoerg * input (i.e., it is in graphics mode) 967680Sjoerg */ 974Srgrimes 986731Sbdestatic u_char cn_is_open; /* nonzero if logical console is open */ 996731Sbdestatic u_char cn_phys_is_open; /* nonzero if physical console is open */ 1005764Sbdestatic d_close_t *cn_phys_close; /* physical device close function */ 1015764Sbdestatic d_open_t *cn_phys_open; /* physical device open function */ 1025764Sbdestatic struct consdev *cn_tab; /* physical console device info */ 1037588Sjoergstatic struct tty *cn_tp; /* physical console tty struct */ 10412675Sjulian#ifdef DEVFS 10512675Sjulianvoid *cn_devfs_token; /* represents the devfs entry */ 10612675Sjulian#endif /* DEVFS */ 1075764Sbde 108798Swollmanvoid 1094Srgrimescninit() 1104Srgrimes{ 11110665Sbde struct consdev *best_cp, *cp; 1124Srgrimes 1134Srgrimes /* 11410665Sbde * Find the first console with the highest priority. 1154Srgrimes */ 11610665Sbde best_cp = NULL; 1174Srgrimes for (cp = constab; cp->cn_probe; cp++) { 1184Srgrimes (*cp->cn_probe)(cp); 1194Srgrimes if (cp->cn_pri > CN_DEAD && 12010665Sbde (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 12110665Sbde best_cp = cp; 1224Srgrimes } 12310665Sbde 1244Srgrimes /* 12510665Sbde * If no console, give up. 1264Srgrimes */ 12710665Sbde if (best_cp == NULL) { 12810665Sbde cn_tab = best_cp; 1294Srgrimes return; 13010665Sbde } 13110665Sbde 1324Srgrimes /* 13310665Sbde * Initialize console, then attach to it. This ordering allows 13410665Sbde * debugging using the previous console, if any. 13510665Sbde * XXX if there was a previous console, then its driver should 13610665Sbde * be informed when we forget about it. 13710665Sbde */ 13810665Sbde (*best_cp->cn_init)(best_cp); 13910665Sbde cn_tab = best_cp; 14010665Sbde} 14110665Sbde 14210665Sbdevoid 14310665Sbdecninit_finish() 14410665Sbde{ 14510665Sbde struct cdevsw *cdp; 14610665Sbde 14710665Sbde if (cn_tab == NULL) 14810665Sbde return; 14910665Sbde 15010665Sbde /* 1515764Sbde * Hook the open and close functions. 1525764Sbde */ 1535764Sbde cdp = &cdevsw[major(cn_tab->cn_dev)]; 1545764Sbde cn_phys_close = cdp->d_close; 1555764Sbde cdp->d_close = cnclose; 1565764Sbde cn_phys_open = cdp->d_open; 1575764Sbde cdp->d_open = cnopen; 1587588Sjoerg cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 15912701Sphk cn_dev_t = cn_tp->t_dev; 1604Srgrimes} 1614Srgrimes 16212675Sjulianstatic int 1634Srgrimescnopen(dev, flag, mode, p) 1644Srgrimes dev_t dev; 1654Srgrimes int flag, mode; 1664Srgrimes struct proc *p; 1674Srgrimes{ 1685764Sbde dev_t cndev, physdev; 1695764Sbde int retval; 1701007Sdg 1714Srgrimes if (cn_tab == NULL) 1724Srgrimes return (0); 1735764Sbde cndev = cn_tab->cn_dev; 1745764Sbde physdev = (major(dev) == major(cndev) ? dev : cndev); 1755764Sbde retval = (*cn_phys_open)(physdev, flag, mode, p); 1765764Sbde if (retval == 0) { 1775764Sbde if (dev == cndev) 1785764Sbde cn_phys_is_open = 1; 1795764Sbde else if (physdev == cndev) 1805764Sbde cn_is_open = 1; 1815764Sbde } 1825764Sbde return (retval); 1834Srgrimes} 1848876Srgrimes 18512675Sjulianstatic int 1864Srgrimescnclose(dev, flag, mode, p) 1874Srgrimes dev_t dev; 1884Srgrimes int flag, mode; 1894Srgrimes struct proc *p; 1904Srgrimes{ 1915764Sbde dev_t cndev; 1921007Sdg 1934Srgrimes if (cn_tab == NULL) 1944Srgrimes return (0); 1955764Sbde cndev = cn_tab->cn_dev; 1965764Sbde if (dev == cndev) { 1977588Sjoerg /* the physical device is about to be closed */ 1985764Sbde cn_phys_is_open = 0; 1997588Sjoerg if (cn_is_open) { 2007588Sjoerg if (cn_tp) { 2017588Sjoerg /* perform a ttyhalfclose() */ 2027588Sjoerg /* reset session and proc group */ 2037588Sjoerg cn_tp->t_pgrp = NULL; 2047588Sjoerg cn_tp->t_session = NULL; 2057588Sjoerg } 2065764Sbde return (0); 2077588Sjoerg } 2085764Sbde } else if (major(dev) != major(cndev)) { 2097588Sjoerg /* the logical console is about to be closed */ 2105764Sbde cn_is_open = 0; 2115764Sbde if (cn_phys_is_open) 2125764Sbde return (0); 2135764Sbde dev = cndev; 2145764Sbde } 2155764Sbde return ((*cn_phys_close)(dev, flag, mode, p)); 2164Srgrimes} 2178876Srgrimes 21812675Sjulianstatic int 2194Srgrimescnread(dev, uio, flag) 2204Srgrimes dev_t dev; 2214Srgrimes struct uio *uio; 222798Swollman int flag; 2234Srgrimes{ 2244Srgrimes if (cn_tab == NULL) 2254Srgrimes return (0); 2264Srgrimes dev = cn_tab->cn_dev; 2274Srgrimes return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); 2284Srgrimes} 2298876Srgrimes 23012675Sjulianstatic int 2314Srgrimescnwrite(dev, uio, flag) 2324Srgrimes dev_t dev; 2334Srgrimes struct uio *uio; 234798Swollman int flag; 2354Srgrimes{ 2364Srgrimes if (cn_tab == NULL) 2374Srgrimes return (0); 2381021Sdg if (constty) 2394Srgrimes dev = constty->t_dev; 2404Srgrimes else 2414Srgrimes dev = cn_tab->cn_dev; 2424Srgrimes return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); 2434Srgrimes} 2448876Srgrimes 24512675Sjulianstatic int 2464Srgrimescnioctl(dev, cmd, data, flag, p) 2474Srgrimes dev_t dev; 248798Swollman int cmd; 2494Srgrimes caddr_t data; 250798Swollman int flag; 2514Srgrimes struct proc *p; 2524Srgrimes{ 2534Srgrimes int error; 2544Srgrimes 2554Srgrimes if (cn_tab == NULL) 2564Srgrimes return (0); 2574Srgrimes /* 2584Srgrimes * Superuser can always use this to wrest control of console 2594Srgrimes * output from the "virtual" console. 2604Srgrimes */ 2614Srgrimes if (cmd == TIOCCONS && constty) { 2624Srgrimes error = suser(p->p_ucred, (u_short *) NULL); 2634Srgrimes if (error) 2644Srgrimes return (error); 2654Srgrimes constty = NULL; 2664Srgrimes return (0); 2674Srgrimes } 2684Srgrimes dev = cn_tab->cn_dev; 2694Srgrimes return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); 2704Srgrimes} 2714Srgrimes 27212675Sjulianstatic int 2734Srgrimescnselect(dev, rw, p) 2744Srgrimes dev_t dev; 2754Srgrimes int rw; 2764Srgrimes struct proc *p; 2774Srgrimes{ 2784Srgrimes if (cn_tab == NULL) 2794Srgrimes return (1); 2806712Spst 2816712Spst dev = cn_tab->cn_dev; 2826712Spst 2836712Spst return ((*cdevsw[major(dev)].d_select)(dev, rw, p)); 2844Srgrimes} 2854Srgrimes 286798Swollmanint 2874Srgrimescngetc() 2884Srgrimes{ 2895160Sjoerg int c; 2904Srgrimes if (cn_tab == NULL) 2914Srgrimes return (0); 2925160Sjoerg c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 2935160Sjoerg if (c == '\r') c = '\n'; /* console input is always ICRNL */ 2945160Sjoerg return (c); 2954Srgrimes} 2964Srgrimes 2973728Sphkint 2983728Sphkcncheckc() 2993728Sphk{ 3003728Sphk if (cn_tab == NULL) 3013728Sphk return (0); 3023728Sphk return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 3033728Sphk} 3043728Sphk 305798Swollmanvoid 3064Srgrimescnputc(c) 3074Srgrimes register int c; 3084Srgrimes{ 3094Srgrimes if (cn_tab == NULL) 3104Srgrimes return; 3114Srgrimes if (c) { 3124Srgrimes if (c == '\n') 3134Srgrimes (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 3149217Sbde (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 3154Srgrimes } 3164Srgrimes} 3174Srgrimes 318718Swollmanint 319718Swollmanpg(const char *p, ...) { 320718Swollman va_list args; 321718Swollman va_start(args, p); 322718Swollman printf("%r\n>", p, args); 323718Swollman return(cngetc()); 3244Srgrimes} 3254Srgrimes 32612517Sjulianstatic cn_devsw_installed = 0; 32712517Sjulian 32812675Sjulianstatic void 32912675Sjuliancn_drvinit(void *unused) 33012517Sjulian{ 33112517Sjulian dev_t dev; 33212517Sjulian 33312517Sjulian if( ! cn_devsw_installed ) { 33412517Sjulian dev = makedev(CDEV_MAJOR,0); 33512517Sjulian cdevsw_add(&dev,&cn_cdevsw,NULL); 33612517Sjulian cn_devsw_installed = 1; 33712517Sjulian#ifdef DEVFS 33812675Sjulian cn_devfs_token = devfs_add_devsw( 33912675Sjulian "/", 34012675Sjulian "console", 34112675Sjulian &cn_cdevsw, 34212675Sjulian 0, 34312675Sjulian DV_CHR, 34412675Sjulian 0, 34512675Sjulian 0, 34612675Sjulian 0640); 34712517Sjulian#endif 34812521Sjulian } 34912517Sjulian} 35012517Sjulian 35112517SjulianSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 35212517Sjulian 35312517Sjulian 354