xref: /openbsd-src/sys/dev/cons.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: cons.c,v 1.26 2016/05/17 23:43:47 bluhm Exp $	*/
2 /*	$NetBSD: cons.c,v 1.30 1996/04/08 19:57:30 jonathan Exp $	*/
3 
4 /*
5  * Copyright (c) 1988 University of Utah.
6  * Copyright (c) 1990, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * the Systems Programming Group of the University of Utah Computer
11  * Science Department.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * from: Utah $Hdr: cons.c 1.7 92/01/21$
38  *
39  *	@(#)cons.c	8.2 (Berkeley) 1/12/94
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/ioctl.h>
45 #include <sys/tty.h>
46 #include <sys/file.h>
47 #include <sys/conf.h>
48 #include <sys/vnode.h>
49 #include <sys/poll.h>
50 
51 #include <dev/cons.h>
52 
53 struct	tty *constty = NULL;		/* virtual console output device */
54 struct	vnode *cn_devvp = NULLVP;	/* vnode for underlying device. */
55 
56 int
57 cnopen(dev_t dev, int flag, int mode, struct proc *p)
58 {
59 	dev_t cndev;
60 
61 	if (cn_tab == NULL)
62 		return (0);
63 
64 	/*
65 	 * always open the 'real' console device, so we don't get nailed
66 	 * later.  This follows normal device semantics; they always get
67 	 * open() calls.
68 	 */
69 	cndev = cn_tab->cn_dev;
70 	if (cndev == NODEV)
71 		return (ENXIO);
72 #ifdef DIAGNOSTIC
73 	if (cndev == dev)
74 		panic("cnopen: recursive");
75 #endif
76 	if (cn_devvp == NULLVP) {
77 		/* try to get a reference on its vnode, but fail silently */
78 		cdevvp(cndev, &cn_devvp);
79 	}
80 	return ((*cdevsw[major(cndev)].d_open)(cndev, flag, mode, p));
81 }
82 
83 int
84 cnclose(dev_t dev, int flag, int mode, struct proc *p)
85 {
86 	struct vnode *vp;
87 
88 	if (cn_tab == NULL)
89 		return (0);
90 
91 	/*
92 	 * If the real console isn't otherwise open, close it.
93 	 * If it's otherwise open, don't close it, because that'll
94 	 * screw up others who have it open.
95 	 */
96 	dev = cn_tab->cn_dev;
97 	if (cn_devvp != NULLVP) {
98 		/* release our reference to real dev's vnode */
99 		vrele(cn_devvp);
100 		cn_devvp = NULLVP;
101 	}
102 	if (vfinddev(dev, VCHR, &vp) && vcount(vp))
103 		return (0);
104 	return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
105 }
106 
107 int
108 cnread(dev_t dev, struct uio *uio, int flag)
109 {
110 
111 	/*
112 	 * If we would redirect input, punt.  This will keep strange
113 	 * things from happening to people who are using the real
114 	 * console.  Nothing should be using /dev/console for
115 	 * input (except a shell in single-user mode, but then,
116 	 * one wouldn't TIOCCONS then).
117 	 */
118 	if (constty != NULL)
119 		return 0;
120 	else if (cn_tab == NULL)
121 		return ENXIO;
122 
123 	dev = cn_tab->cn_dev;
124 	return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
125 }
126 
127 int
128 cnwrite(dev_t dev, struct uio *uio, int flag)
129 {
130 
131 	/*
132 	 * Redirect output, if that's appropriate.
133 	 * If there's no real console, return ENXIO.
134 	 */
135 	if (constty != NULL)
136 		dev = constty->t_dev;
137 	else if (cn_tab == NULL)
138 		return ENXIO;
139 	else
140 		dev = cn_tab->cn_dev;
141 	return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
142 }
143 
144 int
145 cnstop(struct tty *tp, int flag)
146 {
147 	return (0);
148 }
149 
150 int
151 cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag,
152     struct proc *p)
153 {
154 	int error;
155 
156 	/*
157 	 * Superuser can always use this to wrest control of console
158 	 * output from the "virtual" console.
159 	 */
160 	if (cmd == TIOCCONS && constty != NULL) {
161 		error = suser(p, SUSER_NOACCT);
162 		if (error)
163 			return (error);
164 		constty = NULL;
165 		return (0);
166 	}
167 
168 	/*
169 	 * Redirect the ioctl, if that's appropriate.
170 	 * Note that strange things can happen, if a program does
171 	 * ioctls on /dev/console, then the console is redirected
172 	 * out from under it.
173 	 */
174 	if (constty != NULL)
175 		dev = constty->t_dev;
176 	else if (cn_tab == NULL)
177 		return ENXIO;
178 	else
179 		dev = cn_tab->cn_dev;
180 	return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
181 }
182 
183 /*ARGSUSED*/
184 int
185 cnpoll(dev_t dev, int rw, struct proc *p)
186 {
187 
188 	/*
189 	 * Redirect the poll, if that's appropriate.
190 	 * I don't want to think of the possible side effects
191 	 * of console redirection here.
192 	 */
193 	if (constty != NULL)
194 		dev = constty->t_dev;
195 	else if (cn_tab == NULL)
196 		return POLLERR;
197 	else
198 		dev = cn_tab->cn_dev;
199 	return (ttpoll(dev, rw, p));
200 }
201 
202 
203 int
204 cnkqfilter(dev_t dev, struct knote *kn)
205 {
206 
207 	/*
208 	 * Redirect output, if that's appropriate.
209 	 * If there's no real console, return 1.
210 	 */
211 	if (constty != NULL)
212 		dev = constty->t_dev;
213 	else if (cn_tab == NULL)
214 		return (ENXIO);
215 	else
216 		dev = cn_tab->cn_dev;
217 	if (cdevsw[major(dev)].d_kqfilter)
218 		return ((*cdevsw[major(dev)].d_kqfilter)(dev, kn));
219 	return (ENXIO);
220 }
221 
222 int
223 cngetc(void)
224 {
225 
226 	if (cn_tab == NULL)
227 		return (0);
228 	return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
229 }
230 
231 void
232 cnputc(int c)
233 {
234 
235 	if (cn_tab == NULL)
236 		return;
237 
238 	if (c) {
239 		(*cn_tab->cn_putc)(cn_tab->cn_dev, c);
240 		if (c == '\n')
241 			(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
242 	}
243 }
244 
245 void
246 cnpollc(int on)
247 {
248 	static int refcount = 0;
249 
250 	if (cn_tab == NULL)
251 		return;
252 	if (!on)
253 		--refcount;
254 	if (refcount == 0)
255 		(*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
256 	if (on)
257 		++refcount;
258 }
259 
260 void
261 nullcnpollc(dev_t dev, int on)
262 {
263 
264 }
265 
266 void
267 cnbell(u_int pitch, u_int period, u_int volume)
268 {
269 	if (cn_tab == NULL || cn_tab->cn_bell == NULL)
270 		return;
271 
272 	(*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
273 }
274