1 /* $OpenBSD: cons.c,v 1.14 2003/09/23 16:51:12 millert 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/proc.h>
45 #include <sys/user.h>
46 #include <sys/buf.h>
47 #include <sys/ioctl.h>
48 #include <sys/tty.h>
49 #include <sys/file.h>
50 #include <sys/conf.h>
51 #include <sys/vnode.h>
52
53 #include <dev/cons.h>
54
55 struct tty *constty = NULL; /* virtual console output device */
56 struct consdev *cn_tab; /* physical console device info */
57 struct vnode *cn_devvp; /* vnode for underlying device. */
58
59 int
cnopen(dev,flag,mode,p)60 cnopen(dev, flag, mode, p)
61 dev_t dev;
62 int flag, mode;
63 struct proc *p;
64 {
65 dev_t cndev;
66
67 if (cn_tab == NULL)
68 return (0);
69
70 /*
71 * always open the 'real' console device, so we don't get nailed
72 * later. This follows normal device semantics; they always get
73 * open() calls.
74 */
75 cndev = cn_tab->cn_dev;
76 if (cndev == NODEV)
77 return (ENXIO);
78 #ifdef DIAGNOSTIC
79 if (cndev == dev)
80 panic("cnopen: recursive");
81 #endif
82 if (cn_devvp == NULLVP) {
83 /* try to get a reference on its vnode, but fail silently */
84 cdevvp(cndev, &cn_devvp);
85 }
86 return ((*cdevsw[major(cndev)].d_open)(cndev, flag, mode, p));
87 }
88
89 int
cnclose(dev,flag,mode,p)90 cnclose(dev, flag, mode, p)
91 dev_t dev;
92 int flag, mode;
93 struct proc *p;
94 {
95 struct vnode *vp;
96
97 if (cn_tab == NULL)
98 return (0);
99
100 /*
101 * If the real console isn't otherwise open, close it.
102 * If it's otherwise open, don't close it, because that'll
103 * screw up others who have it open.
104 */
105 dev = cn_tab->cn_dev;
106 if (cn_devvp != NULLVP) {
107 /* release our reference to real dev's vnode */
108 vrele(cn_devvp);
109 cn_devvp = NULLVP;
110 }
111 if (vfinddev(dev, VCHR, &vp) && vcount(vp))
112 return (0);
113 return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
114 }
115
116 int
cnread(dev,uio,flag)117 cnread(dev, uio, flag)
118 dev_t dev;
119 struct uio *uio;
120 int flag;
121 {
122
123 /*
124 * If we would redirect input, punt. This will keep strange
125 * things from happening to people who are using the real
126 * console. Nothing should be using /dev/console for
127 * input (except a shell in single-user mode, but then,
128 * one wouldn't TIOCCONS then).
129 */
130 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
131 return 0;
132 else if (cn_tab == NULL)
133 return ENXIO;
134
135 dev = cn_tab->cn_dev;
136 return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
137 }
138
139 int
cnwrite(dev,uio,flag)140 cnwrite(dev, uio, flag)
141 dev_t dev;
142 struct uio *uio;
143 int flag;
144 {
145
146 /*
147 * Redirect output, if that's appropriate.
148 * If there's no real console, return ENXIO.
149 */
150 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
151 dev = constty->t_dev;
152 else if (cn_tab == NULL)
153 return ENXIO;
154 else
155 dev = cn_tab->cn_dev;
156 return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
157 }
158
159 int
cnstop(tp,flag)160 cnstop(tp, flag)
161 struct tty *tp;
162 int flag;
163 {
164 return (0);
165 }
166
167 int
cnioctl(dev,cmd,data,flag,p)168 cnioctl(dev, cmd, data, flag, p)
169 dev_t dev;
170 u_long cmd;
171 caddr_t data;
172 int flag;
173 struct proc *p;
174 {
175 int error;
176
177 /*
178 * Superuser can always use this to wrest control of console
179 * output from the "virtual" console.
180 */
181 if (cmd == TIOCCONS && constty != NULL) {
182 error = suser(p, SUSER_NOACCT);
183 if (error)
184 return (error);
185 constty = NULL;
186 return (0);
187 }
188
189 /*
190 * Redirect the ioctl, if that's appropriate.
191 * Note that strange things can happen, if a program does
192 * ioctls on /dev/console, then the console is redirected
193 * out from under it.
194 */
195 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
196 dev = constty->t_dev;
197 else if (cn_tab == NULL)
198 return ENXIO;
199 else
200 dev = cn_tab->cn_dev;
201 return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
202 }
203
204 /*ARGSUSED*/
205 int
cnpoll(dev,rw,p)206 cnpoll(dev, rw, p)
207 dev_t dev;
208 int rw;
209 struct proc *p;
210 {
211
212 /*
213 * Redirect the poll, if that's appropriate.
214 * I don't want to think of the possible side effects
215 * of console redirection here.
216 */
217 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
218 dev = constty->t_dev;
219 else if (cn_tab == NULL)
220 return ENXIO;
221 else
222 dev = cn_tab->cn_dev;
223 return (ttpoll(cn_tab->cn_dev, rw, p));
224 }
225
226
227 int
cnkqfilter(dev,kn)228 cnkqfilter(dev, kn)
229 dev_t dev;
230 struct knote *kn;
231 {
232
233 /*
234 * Redirect output, if that's appropriate.
235 * If there's no real console, return 1.
236 */
237 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
238 dev = constty->t_dev;
239 else if (cn_tab == NULL)
240 return (1);
241 else
242 dev = cn_tab->cn_dev;
243 if (cdevsw[major(dev)].d_type & D_KQFILTER)
244 return ((*cdevsw[major(dev)].d_kqfilter)(dev, kn));
245 return (1);
246 }
247
248 int
cngetc()249 cngetc()
250 {
251
252 if (cn_tab == NULL)
253 return (0);
254 return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
255 }
256
257 void
cnputc(c)258 cnputc(c)
259 register int c;
260 {
261
262 if (cn_tab == NULL)
263 return;
264
265 if (c) {
266 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
267 if (c == '\n')
268 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
269 }
270 }
271
272 void
cnpollc(on)273 cnpollc(on)
274 int on;
275 {
276 static int refcount = 0;
277
278 if (cn_tab == NULL)
279 return;
280 if (!on)
281 --refcount;
282 if (refcount == 0)
283 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
284 if (on)
285 ++refcount;
286 }
287
288 void
nullcnpollc(dev,on)289 nullcnpollc(dev, on)
290 dev_t dev;
291 int on;
292 {
293
294 }
295
296 void
cnbell(pitch,period,volume)297 cnbell(pitch, period, volume)
298 u_int pitch, period, volume;
299 {
300 if (cn_tab == NULL || cn_tab->cn_bell == NULL)
301 return;
302
303 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
304 }
305