kern_cons.c revision 10665
1/*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	from: @(#)cons.c	7.2 (Berkeley) 5/9/91
39 *	$Id: cons.c,v 1.32 1995/09/09 18:09:44 davidg Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/conf.h>
45#include <sys/proc.h>
46#include <sys/tty.h>
47
48#include <machine/cons.h>
49#include <machine/stdarg.h>
50
51/* XXX this should be config(8)ed. */
52#include "sc.h"
53#include "vt.h"
54#include "sio.h"
55static struct consdev constab[] = {
56#if NSC > 0 || NVT > 0
57	{ pccnprobe,	pccninit,	pccngetc,	pccncheckc,	pccnputc },
58#endif
59#if NSIO > 0
60	{ siocnprobe,	siocninit,	siocngetc,	siocncheckc,	siocnputc },
61#endif
62	{ 0 },
63};
64
65struct	tty *constty = 0;	/* virtual console output device */
66struct	tty *cn_tty;		/* XXX: console tty struct for tprintf */
67int	cons_unavail = 0;	/* XXX:
68				 * physical console not available for
69				 * input (i.e., it is in graphics mode)
70				 */
71
72static u_char cn_is_open;	/* nonzero if logical console is open */
73static u_char cn_phys_is_open;	/* nonzero if physical console is open */
74static d_close_t *cn_phys_close;	/* physical device close function */
75static d_open_t *cn_phys_open;	/* physical device open function */
76static struct consdev *cn_tab;	/* physical console device info */
77static struct tty *cn_tp;	/* physical console tty struct */
78
79#ifdef DEVFS
80#include <sys/kernel.h>
81#include <sys/devfsext.h>
82
83static void cndev_init __P((void *));
84SYSINIT(cndev, SI_SUB_DEVFS, SI_ORDER_ANY, cndev_init, NULL)
85
86static void
87cndev_init(dummy)
88	void *dummy;
89{
90  void * x;
91/*            path	name		devsw   minor	type   uid gid perm*/
92   x=dev_add("/misc",	"console",	cnopen, 0,	DV_CHR, 0,  0, 0640);
93}
94#endif /* DEVFS */
95
96void
97cninit()
98{
99	struct consdev *best_cp, *cp;
100
101	/*
102	 * Find the first console with the highest priority.
103	 */
104	best_cp = NULL;
105	for (cp = constab; cp->cn_probe; cp++) {
106		(*cp->cn_probe)(cp);
107		if (cp->cn_pri > CN_DEAD &&
108		    (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
109			best_cp = cp;
110	}
111
112	/*
113	 * If no console, give up.
114	 */
115	if (best_cp == NULL) {
116		cn_tab = best_cp;
117		return;
118	}
119
120	/*
121	 * Initialize console, then attach to it.  This ordering allows
122	 * debugging using the previous console, if any.
123	 * XXX if there was a previous console, then its driver should
124	 * be informed when we forget about it.
125	 */
126	(*best_cp->cn_init)(best_cp);
127	cn_tab = best_cp;
128}
129
130void
131cninit_finish()
132{
133	struct cdevsw *cdp;
134
135	if (cn_tab == NULL)
136		return;
137
138	/*
139	 * Hook the open and close functions.
140	 */
141	cdp = &cdevsw[major(cn_tab->cn_dev)];
142	cn_phys_close = cdp->d_close;
143	cdp->d_close = cnclose;
144	cn_phys_open = cdp->d_open;
145	cdp->d_open = cnopen;
146	cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
147	/*
148	 * XXX there are too many tty pointers.  cn_tty is only used for
149	 * sysctl(CPU_CONSDEV) (not for tprintf like the above comment
150	 * says).  cn_tp in struct consdev hasn't been initialized
151	 * (except statically to NULL) or used (except to initialize
152	 * cn_tty to the wrong value) for a year or two.
153	 */
154	cn_tty = cn_tp;
155}
156
157int
158cnopen(dev, flag, mode, p)
159	dev_t dev;
160	int flag, mode;
161	struct proc *p;
162{
163	dev_t cndev, physdev;
164	int retval;
165
166	if (cn_tab == NULL)
167		return (0);
168	cndev = cn_tab->cn_dev;
169	physdev = (major(dev) == major(cndev) ? dev : cndev);
170	retval = (*cn_phys_open)(physdev, flag, mode, p);
171	if (retval == 0) {
172		if (dev == cndev)
173			cn_phys_is_open = 1;
174		else if (physdev == cndev)
175			cn_is_open = 1;
176	}
177	return (retval);
178}
179
180int
181cnclose(dev, flag, mode, p)
182	dev_t dev;
183	int flag, mode;
184	struct proc *p;
185{
186	dev_t cndev;
187
188	if (cn_tab == NULL)
189		return (0);
190	cndev = cn_tab->cn_dev;
191	if (dev == cndev) {
192		/* the physical device is about to be closed */
193		cn_phys_is_open = 0;
194		if (cn_is_open) {
195			if (cn_tp) {
196				/* perform a ttyhalfclose() */
197				/* reset session and proc group */
198				cn_tp->t_pgrp = NULL;
199				cn_tp->t_session = NULL;
200			}
201			return (0);
202		}
203	} else if (major(dev) != major(cndev)) {
204		/* the logical console is about to be closed */
205		cn_is_open = 0;
206		if (cn_phys_is_open)
207			return (0);
208		dev = cndev;
209	}
210	return ((*cn_phys_close)(dev, flag, mode, p));
211}
212
213int
214cnread(dev, uio, flag)
215	dev_t dev;
216	struct uio *uio;
217	int flag;
218{
219	if (cn_tab == NULL)
220		return (0);
221	dev = cn_tab->cn_dev;
222	return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
223}
224
225int
226cnwrite(dev, uio, flag)
227	dev_t dev;
228	struct uio *uio;
229	int flag;
230{
231	if (cn_tab == NULL)
232		return (0);
233	if (constty)
234		dev = constty->t_dev;
235	else
236		dev = cn_tab->cn_dev;
237	return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
238}
239
240int
241cnioctl(dev, cmd, data, flag, p)
242	dev_t dev;
243	int cmd;
244	caddr_t data;
245	int flag;
246	struct proc *p;
247{
248	int error;
249
250	if (cn_tab == NULL)
251		return (0);
252	/*
253	 * Superuser can always use this to wrest control of console
254	 * output from the "virtual" console.
255	 */
256	if (cmd == TIOCCONS && constty) {
257		error = suser(p->p_ucred, (u_short *) NULL);
258		if (error)
259			return (error);
260		constty = NULL;
261		return (0);
262	}
263	dev = cn_tab->cn_dev;
264	return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
265}
266
267int
268cnselect(dev, rw, p)
269	dev_t dev;
270	int rw;
271	struct proc *p;
272{
273	if (cn_tab == NULL)
274		return (1);
275
276	dev = cn_tab->cn_dev;
277
278	return ((*cdevsw[major(dev)].d_select)(dev, rw, p));
279}
280
281int
282cngetc()
283{
284	int c;
285	if (cn_tab == NULL)
286		return (0);
287	c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
288	if (c == '\r') c = '\n'; /* console input is always ICRNL */
289	return (c);
290}
291
292int
293cncheckc()
294{
295	if (cn_tab == NULL)
296		return (0);
297	return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
298}
299
300void
301cnputc(c)
302	register int c;
303{
304	if (cn_tab == NULL)
305		return;
306	if (c) {
307		if (c == '\n')
308			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
309		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
310	}
311}
312
313int
314pg(const char *p, ...) {
315  va_list args;
316  va_start(args, p);
317  printf("%r\n>", p, args);
318  return(cngetc());
319}
320
321
322