kern_cons.c revision 12701
1191783Srmacklem/* 2191783Srmacklem * Copyright (c) 1988 University of Utah. 3191783Srmacklem * Copyright (c) 1991 The Regents of the University of California. 4191783Srmacklem * All rights reserved. 5191783Srmacklem * 6191783Srmacklem * This code is derived from software contributed to Berkeley by 7191783Srmacklem * the Systems Programming Group of the University of Utah Computer 8191783Srmacklem * Science Department. 9191783Srmacklem * 10191783Srmacklem * Redistribution and use in source and binary forms, with or without 11191783Srmacklem * modification, are permitted provided that the following conditions 12191783Srmacklem * are met: 13191783Srmacklem * 1. Redistributions of source code must retain the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer. 15191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 16191783Srmacklem * notice, this list of conditions and the following disclaimer in the 17191783Srmacklem * documentation and/or other materials provided with the distribution. 18191783Srmacklem * 3. All advertising materials mentioning features or use of this software 19191783Srmacklem * must display the following acknowledgement: 20191783Srmacklem * This product includes software developed by the University of 21191783Srmacklem * California, Berkeley and its contributors. 22191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 23191783Srmacklem * may be used to endorse or promote products derived from this software 24191783Srmacklem * without specific prior written permission. 25191783Srmacklem * 26191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36191783Srmacklem * SUCH DAMAGE. 37191783Srmacklem * 38191783Srmacklem * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 39191783Srmacklem * $Id: cons.c,v 1.38 1995/12/08 23:20:00 phk Exp $ 40191783Srmacklem */ 41191783Srmacklem 42191783Srmacklem#include <sys/param.h> 43191783Srmacklem#ifdef DEVFS 44191783Srmacklem#include <sys/devfsext.h> 45192503Srmacklem#endif /*DEVFS*/ 46192503Srmacklem#include <sys/systm.h> 47191783Srmacklem#include <sys/conf.h> 48191783Srmacklem#include <sys/kernel.h> 49191783Srmacklem#include <sys/sysctl.h> 50191783Srmacklem#include <sys/proc.h> 51191783Srmacklem#include <sys/tty.h> 52191783Srmacklem 53191783Srmacklem#include <machine/cpu.h> 54191783Srmacklem#include <machine/cons.h> 55191783Srmacklem#include <machine/stdarg.h> 56191783Srmacklem 57191783Srmacklem/* XXX this should be config(8)ed. */ 58191783Srmacklem#include "sc.h" 59191783Srmacklem#include "vt.h" 60191783Srmacklem#include "sio.h" 61192503Srmacklemstatic struct consdev constab[] = { 62191783Srmacklem#if NSC > 0 63192255Srmacklem { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc }, 64192255Srmacklem#endif 65191783Srmacklem#if NVT > 0 66191783Srmacklem { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc }, 67191783Srmacklem#endif 68191783Srmacklem#if NSIO > 0 69191783Srmacklem { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc }, 70192255Srmacklem#endif 71192255Srmacklem { 0 }, 72191783Srmacklem}; 73192255Srmacklem 74192255Srmacklemstatic d_open_t cnopen; 75192255Srmacklemstatic d_close_t cnclose; 76192255Srmacklemstatic d_read_t cnread; 77192255Srmacklemstatic d_write_t cnwrite; 78192255Srmacklemstatic d_ioctl_t cnioctl; 79192255Srmacklemstatic d_select_t cnselect; 80192255Srmacklem 81192255Srmacklem#define CDEV_MAJOR 0 82192255Srmacklemstatic struct cdevsw cn_cdevsw = 83191783Srmacklem { cnopen, cnclose, cnread, cnwrite, /*0*/ 84191783Srmacklem cnioctl, nullstop, nullreset, nodevtotty,/* console */ 85191783Srmacklem cnselect, nommap, NULL, "console", NULL, -1 }; 86191783Srmacklem 87191783Srmacklemstruct tty *constty = 0; /* virtual console output device */ 88191783Srmacklem 89191783Srmacklemstatic dev_t cn_dev_t; 90191783SrmacklemSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD, 91191783Srmacklem &cn_dev_t, sizeof cn_dev_t, "T,dev_t", ""); 92191783Srmacklem 93191783Srmacklemint cons_unavail = 0; /* XXX: 94191783Srmacklem * physical console not available for 95191783Srmacklem * input (i.e., it is in graphics mode) 96191783Srmacklem */ 97191783Srmacklem 98191783Srmacklemstatic u_char cn_is_open; /* nonzero if logical console is open */ 99191783Srmacklemstatic u_char cn_phys_is_open; /* nonzero if physical console is open */ 100191783Srmacklemstatic d_close_t *cn_phys_close; /* physical device close function */ 101191783Srmacklemstatic d_open_t *cn_phys_open; /* physical device open function */ 102191783Srmacklemstatic struct consdev *cn_tab; /* physical console device info */ 103191783Srmacklemstatic struct tty *cn_tp; /* physical console tty struct */ 104191783Srmacklem#ifdef DEVFS 105191783Srmacklemvoid *cn_devfs_token; /* represents the devfs entry */ 106191783Srmacklem#endif /* DEVFS */ 107191783Srmacklem 108191783Srmacklemvoid 109191783Srmacklemcninit() 110191783Srmacklem{ 111191783Srmacklem struct consdev *best_cp, *cp; 112191783Srmacklem 113191783Srmacklem /* 114191783Srmacklem * Find the first console with the highest priority. 115191783Srmacklem */ 116191783Srmacklem best_cp = NULL; 117191783Srmacklem for (cp = constab; cp->cn_probe; cp++) { 118191783Srmacklem (*cp->cn_probe)(cp); 119191783Srmacklem if (cp->cn_pri > CN_DEAD && 120191783Srmacklem (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) 121191783Srmacklem best_cp = cp; 122191783Srmacklem } 123191783Srmacklem 124191783Srmacklem /* 125191783Srmacklem * If no console, give up. 126191783Srmacklem */ 127191783Srmacklem if (best_cp == NULL) { 128191783Srmacklem cn_tab = best_cp; 129191783Srmacklem return; 130191783Srmacklem } 131191783Srmacklem 132191783Srmacklem /* 133191783Srmacklem * Initialize console, then attach to it. This ordering allows 134191783Srmacklem * debugging using the previous console, if any. 135191783Srmacklem * XXX if there was a previous console, then its driver should 136191783Srmacklem * be informed when we forget about it. 137191783Srmacklem */ 138191783Srmacklem (*best_cp->cn_init)(best_cp); 139191783Srmacklem cn_tab = best_cp; 140191783Srmacklem} 141191783Srmacklem 142191783Srmacklemvoid 143191783Srmacklemcninit_finish() 144191783Srmacklem{ 145191783Srmacklem struct cdevsw *cdp; 146191783Srmacklem 147191783Srmacklem if (cn_tab == NULL) 148191783Srmacklem return; 149191783Srmacklem 150191783Srmacklem /* 151191783Srmacklem * Hook the open and close functions. 152191783Srmacklem */ 153191783Srmacklem cdp = &cdevsw[major(cn_tab->cn_dev)]; 154191783Srmacklem cn_phys_close = cdp->d_close; 155191783Srmacklem cdp->d_close = cnclose; 156191783Srmacklem cn_phys_open = cdp->d_open; 157191783Srmacklem cdp->d_open = cnopen; 158191783Srmacklem cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev); 159191783Srmacklem cn_dev_t = cn_tp->t_dev; 160191783Srmacklem} 161191783Srmacklem 162191783Srmacklemstatic int 163191783Srmacklemcnopen(dev, flag, mode, p) 164191783Srmacklem dev_t dev; 165191783Srmacklem int flag, mode; 166191783Srmacklem struct proc *p; 167191783Srmacklem{ 168191783Srmacklem dev_t cndev, physdev; 169191783Srmacklem int retval; 170191783Srmacklem 171191783Srmacklem if (cn_tab == NULL) 172191783Srmacklem return (0); 173191783Srmacklem cndev = cn_tab->cn_dev; 174191783Srmacklem physdev = (major(dev) == major(cndev) ? dev : cndev); 175191783Srmacklem retval = (*cn_phys_open)(physdev, flag, mode, p); 176191783Srmacklem if (retval == 0) { 177191783Srmacklem if (dev == cndev) 178191783Srmacklem cn_phys_is_open = 1; 179191783Srmacklem else if (physdev == cndev) 180191783Srmacklem cn_is_open = 1; 181191783Srmacklem } 182191783Srmacklem return (retval); 183191783Srmacklem} 184191783Srmacklem 185191783Srmacklemstatic int 186191783Srmacklemcnclose(dev, flag, mode, p) 187191783Srmacklem dev_t dev; 188191783Srmacklem int flag, mode; 189191783Srmacklem struct proc *p; 190191783Srmacklem{ 191191783Srmacklem dev_t cndev; 192191783Srmacklem 193191783Srmacklem if (cn_tab == NULL) 194191783Srmacklem return (0); 195191783Srmacklem cndev = cn_tab->cn_dev; 196191783Srmacklem if (dev == cndev) { 197191783Srmacklem /* the physical device is about to be closed */ 198191783Srmacklem cn_phys_is_open = 0; 199191783Srmacklem if (cn_is_open) { 200191783Srmacklem if (cn_tp) { 201191783Srmacklem /* perform a ttyhalfclose() */ 202191783Srmacklem /* reset session and proc group */ 203191783Srmacklem cn_tp->t_pgrp = NULL; 204191783Srmacklem cn_tp->t_session = NULL; 205191783Srmacklem } 206191783Srmacklem return (0); 207191783Srmacklem } 208191783Srmacklem } else if (major(dev) != major(cndev)) { 209191783Srmacklem /* the logical console is about to be closed */ 210191783Srmacklem cn_is_open = 0; 211191783Srmacklem if (cn_phys_is_open) 212191783Srmacklem return (0); 213191783Srmacklem dev = cndev; 214191783Srmacklem } 215191783Srmacklem return ((*cn_phys_close)(dev, flag, mode, p)); 216191783Srmacklem} 217191783Srmacklem 218191783Srmacklemstatic int 219191783Srmacklemcnread(dev, uio, flag) 220191783Srmacklem dev_t dev; 221191783Srmacklem struct uio *uio; 222191783Srmacklem int flag; 223191783Srmacklem{ 224191783Srmacklem if (cn_tab == NULL) 225191783Srmacklem return (0); 226191783Srmacklem dev = cn_tab->cn_dev; 227191783Srmacklem return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); 228191783Srmacklem} 229191783Srmacklem 230191783Srmacklemstatic int 231191783Srmacklemcnwrite(dev, uio, flag) 232191783Srmacklem dev_t dev; 233191783Srmacklem struct uio *uio; 234191783Srmacklem int flag; 235191783Srmacklem{ 236191783Srmacklem if (cn_tab == NULL) 237191783Srmacklem return (0); 238191783Srmacklem if (constty) 239191783Srmacklem dev = constty->t_dev; 240191783Srmacklem else 241191783Srmacklem dev = cn_tab->cn_dev; 242191783Srmacklem return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); 243191783Srmacklem} 244191783Srmacklem 245191783Srmacklemstatic int 246191783Srmacklemcnioctl(dev, cmd, data, flag, p) 247191783Srmacklem dev_t dev; 248191783Srmacklem int cmd; 249191783Srmacklem caddr_t data; 250191783Srmacklem int flag; 251191783Srmacklem struct proc *p; 252191783Srmacklem{ 253191783Srmacklem int error; 254191783Srmacklem 255191783Srmacklem if (cn_tab == NULL) 256191783Srmacklem return (0); 257191783Srmacklem /* 258191783Srmacklem * Superuser can always use this to wrest control of console 259191783Srmacklem * output from the "virtual" console. 260191783Srmacklem */ 261191783Srmacklem if (cmd == TIOCCONS && constty) { 262191783Srmacklem error = suser(p->p_ucred, (u_short *) NULL); 263191783Srmacklem if (error) 264191783Srmacklem return (error); 265191783Srmacklem constty = NULL; 266191783Srmacklem return (0); 267191783Srmacklem } 268191783Srmacklem dev = cn_tab->cn_dev; 269191783Srmacklem return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); 270191783Srmacklem} 271191783Srmacklem 272191783Srmacklemstatic int 273191783Srmacklemcnselect(dev, rw, p) 274191783Srmacklem dev_t dev; 275191783Srmacklem int rw; 276191783Srmacklem struct proc *p; 277191783Srmacklem{ 278191783Srmacklem if (cn_tab == NULL) 279191783Srmacklem return (1); 280191783Srmacklem 281191783Srmacklem dev = cn_tab->cn_dev; 282191783Srmacklem 283191783Srmacklem return ((*cdevsw[major(dev)].d_select)(dev, rw, p)); 284191783Srmacklem} 285191783Srmacklem 286191783Srmacklemint 287191783Srmacklemcngetc() 288191783Srmacklem{ 289191783Srmacklem int c; 290191783Srmacklem if (cn_tab == NULL) 291191783Srmacklem return (0); 292191783Srmacklem c = (*cn_tab->cn_getc)(cn_tab->cn_dev); 293191783Srmacklem if (c == '\r') c = '\n'; /* console input is always ICRNL */ 294191783Srmacklem return (c); 295191783Srmacklem} 296191783Srmacklem 297191783Srmacklemint 298191783Srmacklemcncheckc() 299191783Srmacklem{ 300191783Srmacklem if (cn_tab == NULL) 301191783Srmacklem return (0); 302191783Srmacklem return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); 303191783Srmacklem} 304191783Srmacklem 305191783Srmacklemvoid 306191783Srmacklemcnputc(c) 307191783Srmacklem register int c; 308191783Srmacklem{ 309191783Srmacklem if (cn_tab == NULL) 310191783Srmacklem return; 311191783Srmacklem if (c) { 312191783Srmacklem if (c == '\n') 313191783Srmacklem (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 314191783Srmacklem (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 315191783Srmacklem } 316191783Srmacklem} 317191783Srmacklem 318191783Srmacklemint 319191783Srmacklempg(const char *p, ...) { 320191783Srmacklem va_list args; 321191783Srmacklem va_start(args, p); 322191783Srmacklem printf("%r\n>", p, args); 323191783Srmacklem return(cngetc()); 324191783Srmacklem} 325191783Srmacklem 326191783Srmacklemstatic cn_devsw_installed = 0; 327191783Srmacklem 328191783Srmacklemstatic void 329191783Srmacklemcn_drvinit(void *unused) 330191783Srmacklem{ 331191783Srmacklem dev_t dev; 332191783Srmacklem 333191783Srmacklem if( ! cn_devsw_installed ) { 334191783Srmacklem dev = makedev(CDEV_MAJOR,0); 335191783Srmacklem cdevsw_add(&dev,&cn_cdevsw,NULL); 336191783Srmacklem cn_devsw_installed = 1; 337191783Srmacklem#ifdef DEVFS 338191783Srmacklem cn_devfs_token = devfs_add_devsw( 339191783Srmacklem "/", 340191783Srmacklem "console", 341191783Srmacklem &cn_cdevsw, 342191783Srmacklem 0, 343191783Srmacklem DV_CHR, 344191783Srmacklem 0, 345191783Srmacklem 0, 346191783Srmacklem 0640); 347191783Srmacklem#endif 348191783Srmacklem } 349191783Srmacklem} 350191783Srmacklem 351191783SrmacklemSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) 352191783Srmacklem 353191783Srmacklem 354191783Srmacklem