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