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