xref: /netbsd-src/sys/dev/cons.c (revision 08c81a9c2dc8c7300e893321eb65c0925d60871c)
1 /*	$NetBSD: cons.c,v 1.43 2002/09/06 13:18:43 gehenna Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * from: Utah $Hdr: cons.c 1.7 92/01/21$
41  *
42  *	@(#)cons.c	8.2 (Berkeley) 1/12/94
43  */
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.43 2002/09/06 13:18:43 gehenna Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/proc.h>
50 #include <sys/user.h>
51 #include <sys/systm.h>
52 #include <sys/buf.h>
53 #include <sys/ioctl.h>
54 #include <sys/tty.h>
55 #include <sys/file.h>
56 #include <sys/conf.h>
57 #include <sys/vnode.h>
58 
59 #include <dev/cons.h>
60 
61 dev_type_open(cnopen);
62 dev_type_close(cnclose);
63 dev_type_read(cnread);
64 dev_type_write(cnwrite);
65 dev_type_ioctl(cnioctl);
66 dev_type_poll(cnpoll);
67 
68 const struct cdevsw cons_cdevsw = {
69 	cnopen, cnclose, cnread, cnwrite, cnioctl,
70 	nostop, notty, cnpoll, nommap, D_TTY
71 };
72 
73 struct	tty *constty = NULL;	/* virtual console output device */
74 struct	consdev *cn_tab;	/* physical console device info */
75 struct	vnode *cn_devvp;	/* vnode for underlying device. */
76 
77 int
78 cnopen(dev, flag, mode, p)
79 	dev_t dev;
80 	int flag, mode;
81 	struct proc *p;
82 {
83 	const struct cdevsw *cdev;
84 	dev_t cndev;
85 
86 	if (cn_tab == NULL)
87 		return (0);
88 
89 	/*
90 	 * always open the 'real' console device, so we don't get nailed
91 	 * later.  This follows normal device semantics; they always get
92 	 * open() calls.
93 	 */
94 	cndev = cn_tab->cn_dev;
95 	if (cndev == NODEV) {
96 		/*
97 		 * This is most likely an error in the console attach
98 		 * code. Panicing looks better than jumping into nowhere
99 		 * through cdevsw below....
100 		 */
101 		panic("cnopen: no console device\n");
102 	}
103 	if (dev == cndev) {
104 		/*
105 		 * This causes cnopen() to be called recursively, which
106 		 * is generally a bad thing.  It is often caused when
107 		 * dev == 0 and cn_dev has not been set, but was probably
108 		 * initialised to 0.
109 		 */
110 		panic("cnopen: cn_tab->cn_dev == dev\n");
111 	}
112 	cdev = cdevsw_lookup(cndev);
113 	if (cdev == NULL)
114 		return (ENXIO);
115 
116 	if (cn_devvp == NULLVP) {
117 		/* try to get a reference on its vnode, but fail silently */
118 		cdevvp(cndev, &cn_devvp);
119 	}
120 	return ((*cdev->d_open)(cndev, flag, mode, p));
121 }
122 
123 int
124 cnclose(dev, flag, mode, p)
125 	dev_t dev;
126 	int flag, mode;
127 	struct proc *p;
128 {
129 	const struct cdevsw *cdev;
130 	struct vnode *vp;
131 
132 	if (cn_tab == NULL)
133 		return (0);
134 
135 	/*
136 	 * If the real console isn't otherwise open, close it.
137 	 * If it's otherwise open, don't close it, because that'll
138 	 * screw up others who have it open.
139 	 */
140 	dev = cn_tab->cn_dev;
141 	cdev = cdevsw_lookup(dev);
142 	if (cdev == NULL)
143 		return (ENXIO);
144 	if (cn_devvp != NULLVP) {
145 		/* release our reference to real dev's vnode */
146 		vrele(cn_devvp);
147 		cn_devvp = NULLVP;
148 	}
149 	if (vfinddev(dev, VCHR, &vp) && vcount(vp))
150 		return (0);
151 	return ((*cdev->d_close)(dev, flag, mode, p));
152 }
153 
154 int
155 cnread(dev, uio, flag)
156 	dev_t dev;
157 	struct uio *uio;
158 	int flag;
159 {
160 	const struct cdevsw *cdev;
161 
162 	/*
163 	 * If we would redirect input, punt.  This will keep strange
164 	 * things from happening to people who are using the real
165 	 * console.  Nothing should be using /dev/console for
166 	 * input (except a shell in single-user mode, but then,
167 	 * one wouldn't TIOCCONS then).
168 	 */
169 	if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
170 		return 0;
171 	else if (cn_tab == NULL)
172 		return ENXIO;
173 
174 	dev = cn_tab->cn_dev;
175 	cdev = cdevsw_lookup(dev);
176 	if (cdev == NULL)
177 		return (ENXIO);
178 	return ((*cdev->d_read)(dev, uio, flag));
179 }
180 
181 int
182 cnwrite(dev, uio, flag)
183 	dev_t dev;
184 	struct uio *uio;
185 	int flag;
186 {
187 	const struct cdevsw *cdev;
188 
189 	/*
190 	 * Redirect output, if that's appropriate.
191 	 * If there's no real console, return ENXIO.
192 	 */
193 	if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
194 		dev = constty->t_dev;
195 	else if (cn_tab == NULL)
196 		return ENXIO;
197 	else
198 		dev = cn_tab->cn_dev;
199 	cdev = cdevsw_lookup(dev);
200 	if (cdev == NULL)
201 		return (ENXIO);
202 	return ((*cdev->d_write)(dev, uio, flag));
203 }
204 
205 int
206 cnioctl(dev, cmd, data, flag, p)
207 	dev_t dev;
208 	u_long cmd;
209 	caddr_t data;
210 	int flag;
211 	struct proc *p;
212 {
213 	const struct cdevsw *cdev;
214 	int error;
215 
216 	/*
217 	 * Superuser can always use this to wrest control of console
218 	 * output from the "virtual" console.
219 	 */
220 	if (cmd == TIOCCONS && constty != NULL) {
221 		error = suser(p->p_ucred, (u_short *) NULL);
222 		if (error)
223 			return (error);
224 		constty = NULL;
225 		return (0);
226 	}
227 
228 	/*
229 	 * Redirect the ioctl, if that's appropriate.
230 	 * Note that strange things can happen, if a program does
231 	 * ioctls on /dev/console, then the console is redirected
232 	 * out from under it.
233 	 */
234 	if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
235 		dev = constty->t_dev;
236 	else if (cn_tab == NULL)
237 		return ENXIO;
238 	else
239 		dev = cn_tab->cn_dev;
240 	cdev = cdevsw_lookup(dev);
241 	if (cdev == NULL)
242 		return (ENXIO);
243 	return ((*cdev->d_ioctl)(dev, cmd, data, flag, p));
244 }
245 
246 /*ARGSUSED*/
247 int
248 cnpoll(dev, events, p)
249 	dev_t dev;
250 	int events;
251 	struct proc *p;
252 {
253 	const struct cdevsw *cdev;
254 
255 	/*
256 	 * Redirect the poll, if that's appropriate.
257 	 * I don't want to think of the possible side effects
258 	 * of console redirection here.
259 	 */
260 	if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
261 		dev = constty->t_dev;
262 	else if (cn_tab == NULL)
263 		return ENXIO;
264 	else
265 		dev = cn_tab->cn_dev;
266 	cdev = cdevsw_lookup(dev);
267 	if (cdev == NULL)
268 		return (ENXIO);
269 	return ((*cdev->d_poll)(dev, events, p));
270 }
271 
272 int
273 cngetc()
274 {
275 
276 	if (cn_tab == NULL)
277 		return (0);
278 	return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
279 }
280 
281 int
282 cngetsn(cp, size)
283 	char *cp;
284 	int size;
285 {
286 	char *lp;
287 	int c, len;
288 
289 	cnpollc(1);
290 
291 	lp = cp;
292 	len = 0;
293 	for (;;) {
294 		c = cngetc();
295 		switch (c) {
296 		case '\n':
297 		case '\r':
298 			printf("\n");
299 			*lp++ = '\0';
300 			cnpollc(0);
301 			return (len);
302 		case '\b':
303 		case '\177':
304 		case '#':
305 			if (len) {
306 				--len;
307 				--lp;
308 				printf("\b \b");
309 			}
310 			continue;
311 		case '@':
312 		case 'u'&037:	/* CTRL-u */
313 			len = 0;
314 			lp = cp;
315 			printf("\n");
316 			continue;
317 		default:
318 			if (len + 1 >= size || c < ' ') {
319 				printf("\007");
320 				continue;
321 			}
322 			printf("%c", c);
323 			++len;
324 			*lp++ = c;
325 		}
326 	}
327 }
328 
329 void
330 cnputc(c)
331 	int c;
332 {
333 
334 	if (cn_tab == NULL)
335 		return;
336 
337 	if (c) {
338 		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
339 		if (c == '\n')
340 			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
341 	}
342 }
343 
344 void
345 cnpollc(on)
346 	int on;
347 {
348 	static int refcount = 0;
349 
350 	if (cn_tab == NULL)
351 		return;
352 	if (!on)
353 		--refcount;
354 	if (refcount == 0)
355 		(*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
356 	if (on)
357 		++refcount;
358 }
359 
360 void
361 nullcnpollc(dev, on)
362 	dev_t dev;
363 	int on;
364 {
365 
366 }
367 
368 void
369 cnbell(pitch, period, volume)
370 	u_int pitch, period, volume;
371 {
372 
373 	if (cn_tab == NULL || cn_tab->cn_bell == NULL)
374 		return;
375 	(*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
376 }
377