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