kern_cons.c revision 34924
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.56 1998/01/24 02:54:12 eivind Exp $
40 */
41
42#include "opt_devfs.h"
43
44#include <sys/param.h>
45#ifdef DEVFS
46#include <sys/devfsext.h>
47#endif /*DEVFS*/
48#include <sys/systm.h>
49#include <sys/conf.h>
50#include <sys/kernel.h>
51#include <sys/reboot.h>
52#include <sys/sysctl.h>
53#include <sys/proc.h>
54#include <sys/tty.h>
55#include <sys/uio.h>
56
57#include <machine/cpu.h>
58#include <machine/cons.h>
59
60/* XXX this should be config(8)ed. */
61#include "sc.h"
62#include "vt.h"
63#include "sio.h"
64static struct consdev constab[] = {
65#if NSC > 0
66	{ sccnprobe,	sccninit,	sccngetc,	sccncheckc,	sccnputc },
67#endif
68#if NVT > 0
69	{ pccnprobe,	pccninit,	pccngetc,	pccncheckc,	pccnputc },
70#endif
71#if NSIO > 0
72	{ siocnprobe,	siocninit,	siocngetc,	siocncheckc,	siocnputc },
73#endif
74	{ 0 },
75};
76
77static	d_open_t	cnopen;
78static	d_close_t	cnclose;
79static	d_read_t	cnread;
80static	d_write_t	cnwrite;
81static	d_ioctl_t	cnioctl;
82static	d_poll_t	cnpoll;
83
84#define CDEV_MAJOR 0
85static struct cdevsw cn_cdevsw =
86	{ cnopen,	cnclose,	cnread,		cnwrite,	/*0*/
87	  cnioctl,	nullstop,	nullreset,	nodevtotty,/* console */
88	  cnpoll,	nommap,		NULL,	"console",	NULL,	-1 };
89
90static dev_t	cn_dev_t; 	/* seems to be never really used */
91SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD,
92	&cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
93
94static int cn_mute;
95
96int	cons_unavail = 0;	/* XXX:
97				 * physical console not available for
98				 * input (i.e., it is in graphics mode)
99				 */
100
101static u_char cn_is_open;		/* nonzero if logical console is open */
102static int openmode, openflag;		/* how /dev/console was openned */
103static u_char cn_phys_is_open;		/* nonzero if physical device is open */
104static d_close_t *cn_phys_close;	/* physical device close function */
105static d_open_t *cn_phys_open;		/* physical device open function */
106static struct consdev *cn_tab;		/* physical console device info */
107static struct tty *cn_tp;		/* physical console tty struct */
108#ifdef DEVFS
109static void *cn_devfs_token;		/* represents the devfs entry */
110#endif /* DEVFS */
111
112void
113cninit()
114{
115	struct consdev *best_cp, *cp;
116
117	/*
118	 * Find the first console with the highest priority.
119	 */
120	best_cp = NULL;
121	for (cp = constab; cp->cn_probe; cp++) {
122		(*cp->cn_probe)(cp);
123		if (cp->cn_pri > CN_DEAD &&
124		    (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
125			best_cp = cp;
126	}
127
128	/*
129	 * Check if we should mute the console (for security reasons perhaps)
130	 * It can be changes dynamically using sysctl kern.consmute
131	 * once we are up and going.
132	 *
133	 */
134        cn_mute = ((boothowto & (RB_MUTE
135			|RB_SINGLE
136			|RB_VERBOSE
137			|RB_ASKNAME
138			|RB_CONFIG)) == RB_MUTE);
139
140	/*
141	 * If no console, give up.
142	 */
143	if (best_cp == NULL) {
144		cn_tab = best_cp;
145		return;
146	}
147
148	/*
149	 * Initialize console, then attach to it.  This ordering allows
150	 * debugging using the previous console, if any.
151	 * XXX if there was a previous console, then its driver should
152	 * be informed when we forget about it.
153	 */
154	(*best_cp->cn_init)(best_cp);
155	cn_tab = best_cp;
156}
157
158void
159cninit_finish()
160{
161	struct cdevsw *cdp;
162
163	if ((cn_tab == NULL) || cn_mute)
164		return;
165
166	/*
167	 * Hook the open and close functions.
168	 */
169	cdp = cdevsw[major(cn_tab->cn_dev)];
170	cn_phys_close = cdp->d_close;
171	cdp->d_close = cnclose;
172	cn_phys_open = cdp->d_open;
173	cdp->d_open = cnopen;
174	cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
175	cn_dev_t = cn_tp->t_dev;
176}
177
178static void
179cnuninit(void)
180{
181	struct cdevsw *cdp;
182
183	if (cn_tab == NULL)
184		return;
185
186	/*
187	 * Unhook the open and close functions.
188	 */
189	cdp = cdevsw[major(cn_tab->cn_dev)];
190	cdp->d_close = cn_phys_close;
191	cn_phys_close = NULL;
192	cdp->d_open = cn_phys_open;
193	cn_phys_open = NULL;
194	cn_tp = NULL;
195	cn_dev_t = 0;
196}
197
198/*
199 * User has changed the state of the console muting.
200 * This may require us to open or close the device in question.
201 */
202static int
203sysctl_kern_consmute SYSCTL_HANDLER_ARGS
204{
205	int error;
206	int ocn_mute;
207
208	ocn_mute = cn_mute;
209	error = sysctl_handle_int(oidp, &cn_mute, 0, req);
210	if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
211		if(ocn_mute && !cn_mute) {
212			/*
213			 * going from muted to unmuted.. open the physical dev
214			 * if the console has been openned
215			 */
216			cninit_finish();
217			if(cn_is_open)
218				/* XXX curproc is not what we want really */
219				error = cnopen(cn_dev_t, openflag,
220					openmode, curproc);
221			/* if it failed, back it out */
222			if ( error != 0) cnuninit();
223		} else if (!ocn_mute && cn_mute) {
224			/*
225			 * going from unmuted to muted.. close the physical dev
226			 * if it's only open via /dev/console
227			 */
228			if(cn_is_open)
229				error = cnclose(cn_dev_t, openflag,
230					openmode, curproc);
231			if ( error == 0) cnuninit();
232		}
233		if (error != 0) {
234			/*
235	 		 * back out the change if there was an error
236			 */
237			cn_mute = ocn_mute;
238		}
239	}
240	return (error);
241}
242
243SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
244	0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
245
246static int
247cnopen(dev, flag, mode, p)
248	dev_t dev;
249	int flag, mode;
250	struct proc *p;
251{
252	dev_t cndev, physdev;
253	int retval = 0;
254
255	if (cn_tab == NULL)
256		return (0);
257	cndev = cn_tab->cn_dev;
258	physdev = (major(dev) == major(cndev) ? dev : cndev);
259	/*
260	 * If mute is active, then non console opens don't get here
261	 * so we don't need to check for that. They
262	 * bypass this and go straight to the device.
263	 */
264	if(!cn_mute)
265		retval = (*cn_phys_open)(physdev, flag, mode, p);
266	if (retval == 0) {
267		/*
268		 * check if we openned it via /dev/console or
269		 * via the physical entry (e.g. /dev/sio0).
270		 */
271		if (dev == cndev)
272			cn_phys_is_open = 1;
273		else if (physdev == cndev) {
274			openmode = mode;
275			openflag = flag;
276			cn_is_open = 1;
277		}
278	}
279	return (retval);
280}
281
282static int
283cnclose(dev, flag, mode, p)
284	dev_t dev;
285	int flag, mode;
286	struct proc *p;
287{
288	dev_t cndev;
289
290	if (cn_tab == NULL)
291		return (0);
292	cndev = cn_tab->cn_dev;
293	/*
294	 * act appropriatly depending on whether it's /dev/console
295	 * or the pysical device (e.g. /dev/sio) that's being closed.
296	 * in either case, don't actually close the device unless
297	 * both are closed.
298	 */
299	if (dev == cndev) {
300		/* the physical device is about to be closed */
301		cn_phys_is_open = 0;
302		if (cn_is_open) {
303			if (cn_tp) {
304				/* perform a ttyhalfclose() */
305				/* reset session and proc group */
306				cn_tp->t_pgrp = NULL;
307				cn_tp->t_session = NULL;
308			}
309			return (0);
310		}
311	} else if (major(dev) != major(cndev)) {
312		/* the logical console is about to be closed */
313		cn_is_open = 0;
314		if (cn_phys_is_open)
315			return (0);
316		dev = cndev;
317	}
318	if(cn_phys_close)
319		return ((*cn_phys_close)(dev, flag, mode, p));
320	return (0);
321}
322
323static int
324cnread(dev, uio, flag)
325	dev_t dev;
326	struct uio *uio;
327	int flag;
328{
329	if ((cn_tab == NULL) || cn_mute)
330		return (0);
331	dev = cn_tab->cn_dev;
332	return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
333}
334
335static int
336cnwrite(dev, uio, flag)
337	dev_t dev;
338	struct uio *uio;
339	int flag;
340{
341	if ((cn_tab == NULL) || cn_mute) {
342		uio->uio_resid = 0; /* dump the data */
343		return (0);
344	}
345	if (constty)
346		dev = constty->t_dev;
347	else
348		dev = cn_tab->cn_dev;
349	return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
350}
351
352static int
353cnioctl(dev, cmd, data, flag, p)
354	dev_t dev;
355	int cmd;
356	caddr_t data;
357	int flag;
358	struct proc *p;
359{
360	int error;
361
362	if ((cn_tab == NULL) || cn_mute)
363		return (0);
364	/*
365	 * Superuser can always use this to wrest control of console
366	 * output from the "virtual" console.
367	 */
368	if (cmd == TIOCCONS && constty) {
369		error = suser(p->p_ucred, (u_short *) NULL);
370		if (error)
371			return (error);
372		constty = NULL;
373		return (0);
374	}
375	dev = cn_tab->cn_dev;
376	return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
377}
378
379static int
380cnpoll(dev, events, p)
381	dev_t dev;
382	int events;
383	struct proc *p;
384{
385	if ((cn_tab == NULL) || cn_mute)
386		return (1);
387
388	dev = cn_tab->cn_dev;
389
390	return ((*cdevsw[major(dev)]->d_poll)(dev, events, p));
391}
392
393int
394cngetc()
395{
396	int c;
397	if ((cn_tab == NULL) || cn_mute)
398		return (-1);
399	c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
400	if (c == '\r') c = '\n'; /* console input is always ICRNL */
401	return (c);
402}
403
404int
405cncheckc()
406{
407	if ((cn_tab == NULL) || cn_mute)
408		return (-1);
409	return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
410}
411
412void
413cnputc(c)
414	register int c;
415{
416	if ((cn_tab == NULL) || cn_mute)
417		return;
418	if (c) {
419		if (c == '\n')
420			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
421		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
422	}
423}
424
425static cn_devsw_installed = 0;
426
427static void
428cn_drvinit(void *unused)
429{
430	dev_t dev;
431
432	if( ! cn_devsw_installed ) {
433		dev = makedev(CDEV_MAJOR,0);
434		cdevsw_add(&dev,&cn_cdevsw,NULL);
435		cn_devsw_installed = 1;
436#ifdef DEVFS
437		cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR,
438						  UID_ROOT, GID_WHEEL, 0600,
439						  "console");
440#endif
441	}
442}
443
444SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
445
446
447