kern_cons.c revision 12813
1193323Sed/*
2193323Sed * Copyright (c) 1988 University of Utah.
3193323Sed * Copyright (c) 1991 The Regents of the University of California.
4193323Sed * All rights reserved.
5193323Sed *
6193323Sed * This code is derived from software contributed to Berkeley by
7193323Sed * the Systems Programming Group of the University of Utah Computer
8193323Sed * Science Department.
9193323Sed *
10193323Sed * Redistribution and use in source and binary forms, with or without
11193323Sed * modification, are permitted provided that the following conditions
12193323Sed * are met:
13193323Sed * 1. Redistributions of source code must retain the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer.
15193323Sed * 2. Redistributions in binary form must reproduce the above copyright
16193323Sed *    notice, this list of conditions and the following disclaimer in the
17193323Sed *    documentation and/or other materials provided with the distribution.
18193323Sed * 3. All advertising materials mentioning features or use of this software
19249423Sdim *    must display the following acknowledgement:
20249423Sdim *	This product includes software developed by the University of
21193323Sed *	California, Berkeley and its contributors.
22193323Sed * 4. Neither the name of the University nor the names of its contributors
23198892Srdivacky *    may be used to endorse or promote products derived from this software
24218893Sdim *    without specific prior written permission.
25249423Sdim *
26249423Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28249423Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29249423Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36193323Sed * SUCH DAMAGE.
37193323Sed *
38193323Sed *	from: @(#)cons.c	7.2 (Berkeley) 5/9/91
39193323Sed *	$Id: cons.c,v 1.39 1995/12/09 20:39:45 phk Exp $
40193323Sed */
41193323Sed
42193323Sed#include <sys/param.h>
43193323Sed#ifdef DEVFS
44193323Sed#include <sys/devfsext.h>
45193323Sed#endif /*DEVFS*/
46193323Sed#include <sys/systm.h>
47193323Sed#include <sys/conf.h>
48198892Srdivacky#include <sys/kernel.h>
49193323Sed#include <sys/sysctl.h>
50193323Sed#include <sys/proc.h>
51193323Sed#include <sys/tty.h>
52212904Sdim
53193323Sed#include <machine/cpu.h>
54193323Sed#include <machine/cons.h>
55193323Sed#include <machine/stdarg.h>
56193323Sed
57212904Sdim/* XXX this should be config(8)ed. */
58193323Sed#include "sc.h"
59212904Sdim#include "vt.h"
60212904Sdim#include "sio.h"
61193323Sedstatic struct consdev constab[] = {
62193323Sed#if NSC > 0
63193323Sed	{ sccnprobe,	sccninit,	sccngetc,	sccncheckc,	sccnputc },
64193323Sed#endif
65193323Sed#if NVT > 0
66193323Sed	{ pccnprobe,	pccninit,	pccngetc,	pccncheckc,	pccnputc },
67193323Sed#endif
68193323Sed#if NSIO > 0
69193323Sed	{ siocnprobe,	siocninit,	siocngetc,	siocncheckc,	siocnputc },
70193323Sed#endif
71193323Sed	{ 0 },
72193323Sed};
73193323Sed
74198892Srdivackystatic	d_open_t	cnopen;
75193323Sedstatic	d_close_t	cnclose;
76193323Sedstatic	d_read_t	cnread;
77212904Sdimstatic	d_write_t	cnwrite;
78193323Sedstatic	d_ioctl_t	cnioctl;
79193323Sedstatic	d_select_t	cnselect;
80193323Sed
81212904Sdim#define CDEV_MAJOR 0
82193323Sedstatic struct cdevsw cn_cdevsw =
83193323Sed	{ cnopen,	cnclose,	cnread,		cnwrite,	/*0*/
84193323Sed	  cnioctl,	nullstop,	nullreset,	nodevtotty,/* console */
85212904Sdim	  cnselect,	nommap,		NULL,	"console",	NULL,	-1 };
86193323Sed
87193323Sedstruct	tty *constty = 0;	/* virtual console output device */
88193323Sed
89212904Sdimstatic dev_t	cn_dev_t;
90193323SedSYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD,
91193323Sed	&cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
92193323Sed
93218893Sdimint	cons_unavail = 0;	/* XXX:
94218893Sdim				 * physical console not available for
95218893Sdim				 * input (i.e., it is in graphics mode)
96193323Sed				 */
97193323Sed
98193323Sedstatic u_char cn_is_open;	/* nonzero if logical console is open */
99193323Sedstatic u_char cn_phys_is_open;	/* nonzero if physical console is open */
100193323Sedstatic d_close_t *cn_phys_close;	/* physical device close function */
101193323Sedstatic d_open_t *cn_phys_open;	/* physical device open function */
102193323Sedstatic struct consdev *cn_tab;	/* physical console device info */
103193323Sedstatic struct tty *cn_tp;	/* physical console tty struct */
104193323Sed#ifdef DEVFS
105193323Sedvoid *cn_devfs_token;		/* represents the devfs entry */
106193323Sed#endif /* DEVFS */
107193323Sed
108193323Sedvoid
109193323Sedcninit()
110193323Sed{
111193323Sed	struct consdev *best_cp, *cp;
112193323Sed
113218893Sdim	/*
114212904Sdim	 * Find the first console with the highest priority.
115218893Sdim	 */
116212904Sdim	best_cp = NULL;
117212904Sdim	for (cp = constab; cp->cn_probe; cp++) {
118212904Sdim		(*cp->cn_probe)(cp);
119193323Sed		if (cp->cn_pri > CN_DEAD &&
120193323Sed		    (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
121193323Sed			best_cp = cp;
122193323Sed	}
123193323Sed
124212904Sdim	/*
125218893Sdim	 * If no console, give up.
126218893Sdim	 */
127193323Sed	if (best_cp == NULL) {
128193323Sed		cn_tab = best_cp;
129218893Sdim		return;
130193323Sed	}
131218893Sdim
132193323Sed	/*
133218893Sdim	 * Initialize console, then attach to it.  This ordering allows
134218893Sdim	 * debugging using the previous console, if any.
135193323Sed	 * XXX if there was a previous console, then its driver should
136193323Sed	 * be informed when we forget about it.
137193323Sed	 */
138193323Sed	(*best_cp->cn_init)(best_cp);
139193323Sed	cn_tab = best_cp;
140212904Sdim}
141218893Sdim
142218893Sdimvoid
143218893Sdimcninit_finish()
144218893Sdim{
145218893Sdim	struct cdevsw *cdp;
146218893Sdim
147218893Sdim	if (cn_tab == NULL)
148218893Sdim		return;
149218893Sdim
150218893Sdim	/*
151218893Sdim	 * Hook the open and close functions.
152193323Sed	 */
153193323Sed	cdp = cdevsw[major(cn_tab->cn_dev)];
154193323Sed	cn_phys_close = cdp->d_close;
155193323Sed	cdp->d_close = cnclose;
156218893Sdim	cn_phys_open = cdp->d_open;
157193323Sed	cdp->d_open = cnopen;
158202878Srdivacky	cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
159202878Srdivacky	cn_dev_t = cn_tp->t_dev;
160202878Srdivacky}
161202878Srdivacky
162212904Sdimstatic int
163212904Sdimcnopen(dev, flag, mode, p)
164202878Srdivacky	dev_t dev;
165202878Srdivacky	int flag, mode;
166202878Srdivacky	struct proc *p;
167202878Srdivacky{
168193323Sed	dev_t cndev, physdev;
169193323Sed	int retval;
170193323Sed
171212904Sdim	if (cn_tab == NULL)
172212904Sdim		return (0);
173212904Sdim	cndev = cn_tab->cn_dev;
174193323Sed	physdev = (major(dev) == major(cndev) ? dev : cndev);
175193323Sed	retval = (*cn_phys_open)(physdev, flag, mode, p);
176193323Sed	if (retval == 0) {
177193323Sed		if (dev == cndev)
178193323Sed			cn_phys_is_open = 1;
179193323Sed		else if (physdev == cndev)
180193323Sed			cn_is_open = 1;
181193323Sed	}
182193323Sed	return (retval);
183193323Sed}
184193323Sed
185193323Sedstatic int
186193323Sedcnclose(dev, flag, mode, p)
187193323Sed	dev_t dev;
188193323Sed	int flag, mode;
189218893Sdim	struct proc *p;
190212904Sdim{
191218893Sdim	dev_t cndev;
192263508Sdim
193218893Sdim	if (cn_tab == NULL)
194218893Sdim		return (0);
195218893Sdim	cndev = cn_tab->cn_dev;
196193323Sed	if (dev == cndev) {
197193323Sed		/* the physical device is about to be closed */
198193323Sed		cn_phys_is_open = 0;
199193323Sed		if (cn_is_open) {
200193323Sed			if (cn_tp) {
201193323Sed				/* perform a ttyhalfclose() */
202193323Sed				/* reset session and proc group */
203193323Sed				cn_tp->t_pgrp = NULL;
204193323Sed				cn_tp->t_session = NULL;
205193323Sed			}
206193323Sed			return (0);
207193323Sed		}
208193323Sed	} else if (major(dev) != major(cndev)) {
209193323Sed		/* the logical console is about to be closed */
210193323Sed		cn_is_open = 0;
211193323Sed		if (cn_phys_is_open)
212193323Sed			return (0);
213193323Sed		dev = cndev;
214193323Sed	}
215193323Sed	return ((*cn_phys_close)(dev, flag, mode, p));
216193323Sed}
217193323Sed
218193323Sedstatic int
219193323Sedcnread(dev, uio, flag)
220193323Sed	dev_t dev;
221193323Sed	struct uio *uio;
222193323Sed	int flag;
223193323Sed{
224193323Sed	if (cn_tab == NULL)
225193323Sed		return (0);
226193323Sed	dev = cn_tab->cn_dev;
227193323Sed	return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
228193323Sed}
229193323Sed
230193323Sedstatic int
231204642Srdivackycnwrite(dev, uio, flag)
232193323Sed	dev_t dev;
233193323Sed	struct uio *uio;
234193323Sed	int flag;
235193323Sed{
236193323Sed	if (cn_tab == NULL)
237193323Sed		return (0);
238193323Sed	if (constty)
239193323Sed		dev = constty->t_dev;
240193323Sed	else
241193323Sed		dev = cn_tab->cn_dev;
242193323Sed	return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
243193323Sed}
244193323Sed
245193323Sedstatic int
246193323Sedcnioctl(dev, cmd, data, flag, p)
247193323Sed	dev_t dev;
248193323Sed	int cmd;
249204642Srdivacky	caddr_t data;
250193323Sed	int flag;
251210299Sed	struct proc *p;
252210299Sed{
253210299Sed	int error;
254193323Sed
255210299Sed	if (cn_tab == NULL)
256193323Sed		return (0);
257193323Sed	/*
258193323Sed	 * Superuser can always use this to wrest control of console
259193323Sed	 * output from the "virtual" console.
260193323Sed	 */
261210299Sed	if (cmd == TIOCCONS && constty) {
262193323Sed		error = suser(p->p_ucred, (u_short *) NULL);
263210299Sed		if (error)
264198090Srdivacky			return (error);
265198090Srdivacky		constty = NULL;
266243830Sdim		return (0);
267210299Sed	}
268210299Sed	dev = cn_tab->cn_dev;
269193323Sed	return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
270193323Sed}
271210299Sed
272210299Sedstatic int
273210299Sedcnselect(dev, rw, p)
274193323Sed	dev_t dev;
275193323Sed	int rw;
276210299Sed	struct proc *p;
277210299Sed{
278210299Sed	if (cn_tab == NULL)
279193323Sed		return (1);
280193323Sed
281193323Sed	dev = cn_tab->cn_dev;
282193323Sed
283193323Sed	return ((*cdevsw[major(dev)]->d_select)(dev, rw, p));
284193323Sed}
285193323Sed
286210299Sedint
287193323Sedcngetc()
288193323Sed{
289193323Sed	int c;
290193323Sed	if (cn_tab == NULL)
291193323Sed		return (0);
292210299Sed	c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
293210299Sed	if (c == '\r') c = '\n'; /* console input is always ICRNL */
294193323Sed	return (c);
295193323Sed}
296193323Sed
297193323Sedint
298193323Sedcncheckc()
299193323Sed{
300193323Sed	if (cn_tab == NULL)
301193323Sed		return (0);
302193323Sed	return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
303193323Sed}
304193323Sed
305193323Sedvoid
306193323Sedcnputc(c)
307193323Sed	register int c;
308193323Sed{
309193323Sed	if (cn_tab == NULL)
310193323Sed		return;
311193323Sed	if (c) {
312210299Sed		if (c == '\n')
313210299Sed			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
314193323Sed		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
315193323Sed	}
316193323Sed}
317193323Sed
318193323Sedint
319193323Sedpg(const char *p, ...) {
320193323Sed  va_list args;
321210299Sed  va_start(args, p);
322193323Sed  printf("%r\n>", p, args);
323193323Sed  return(cngetc());
324193323Sed}
325193323Sed
326193323Sedstatic cn_devsw_installed = 0;
327193323Sed
328193323Sedstatic void
329193323Sedcn_drvinit(void *unused)
330218893Sdim{
331193323Sed	dev_t dev;
332243830Sdim
333193323Sed	if( ! cn_devsw_installed ) {
334193323Sed		dev = makedev(CDEV_MAJOR,0);
335193323Sed		cdevsw_add(&dev,&cn_cdevsw,NULL);
336193323Sed		cn_devsw_installed = 1;
337193323Sed#ifdef DEVFS
338193323Sed		cn_devfs_token = devfs_add_devsw(
339193323Sed			 	"/",
340193323Sed				"console",
341193323Sed				&cn_cdevsw,
342193323Sed				0,
343193323Sed				DV_CHR,
344193323Sed				0,
345193323Sed				0,
346193323Sed				0640);
347193323Sed#endif
348193323Sed	}
349193323Sed}
350193323Sed
351193323SedSYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
352193323Sed
353193323Sed
354193323Sed