cons.c revision 1.40.4.3 1 /* $NetBSD: cons.c,v 1.40.4.3 2001/09/20 11:15:42 fvdl 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/param.h>
46 #include <sys/proc.h>
47 #include <sys/user.h>
48 #include <sys/systm.h>
49 #include <sys/buf.h>
50 #include <sys/ioctl.h>
51 #include <sys/tty.h>
52 #include <sys/file.h>
53 #include <sys/conf.h>
54 #include <sys/vnode.h>
55
56 #include <miscfs/specfs/specdev.h>
57
58 #include <dev/cons.h>
59
60 struct tty *constty = NULL; /* virtual console output device */
61 struct consdev *cn_tab; /* physical console device info */
62
63 int
64 cnopen(devvp, mode, flag, p)
65 struct vnode *devvp;
66 int flag, mode;
67 struct proc *p;
68 {
69 int error;
70 dev_t cndev;
71 struct vnode *vp;
72
73 if (cn_tab == NULL)
74 return (0);
75
76
77 /*
78 * always open the 'real' console device, so we don't get nailed
79 * later. This follows normal device semantics; they always get
80 * open() calls.
81 */
82 cndev = cn_tab->cn_dev;
83 if (cndev == NODEV) {
84 /*
85 * This is most likely an error in the console attach
86 * code. Panicing looks better than jumping into nowhere
87 * through cdevsw below....
88 */
89 panic("cnopen: cn_tab->cn_dev == NODEV\n");
90 }
91 if (devvp->v_rdev == cndev) {
92 /*
93 * This causes cnopen() to be called recursively, which
94 * is generally a bad thing. It is often caused when
95 * dev == 0 and cn_dev has not been set, but was probably
96 * initialised to 0.
97 */
98 panic("cnopen: cn_tab->cn_dev == dev\n");
99 }
100
101 if (vfinddev(cndev, VCHR, &vp) == 0) {
102 error = cdevvp(cndev, &vp);
103 if (error != 0)
104 return error;
105 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
106 } else
107 vget(vp, LK_EXCLUSIVE | LK_RETRY);
108 devvp->v_devcookie = vp;
109
110 error = VOP_OPEN(vp, mode, p->p_ucred, p, NULL);
111 VOP_UNLOCK(vp, 0);
112 if (error != 0)
113 vrele(vp);
114 return error;
115 }
116
117 int
118 cnclose(devvp, flag, mode, p)
119 struct vnode *devvp;
120 int flag, mode;
121 struct proc *p;
122 {
123 struct vnode *vp;
124 int error;
125
126 if (cn_tab == NULL)
127 return (0);
128
129 vp = devvp->v_devcookie;
130
131 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
132 error = VOP_CLOSE(vp, flag, p->p_ucred, p);
133 vput(vp);
134
135 return error;
136 }
137
138 int
139 cnread(devvp, uio, flag)
140 struct vnode *devvp;
141 struct uio *uio;
142 int flag;
143 {
144 int error;
145 struct vnode *vp;
146 struct proc *p = uio->uio_procp;
147
148 /*
149 * If we would redirect input, punt. This will keep strange
150 * things from happening to people who are using the real
151 * console. Nothing should be using /dev/console for
152 * input (except a shell in single-user mode, but then,
153 * one wouldn't TIOCCONS then).
154 */
155 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
156 return 0;
157 else if (cn_tab == NULL)
158 return ENXIO;
159
160 vp = devvp->v_devcookie;
161 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
162 error = VOP_READ(vp, uio, flag, p->p_ucred);
163 VOP_UNLOCK(vp, 0);
164
165 return error;
166 }
167
168 int
169 cnwrite(devvp, uio, flag)
170 struct vnode *devvp;
171 struct uio *uio;
172 int flag;
173 {
174 int error;
175 struct vnode *vp;
176 struct proc *p = uio->uio_procp;
177
178 /*
179 * Redirect output, if that's appropriate.
180 * If there's no real console, return ENXIO.
181 */
182 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
183 vp = constty->t_devvp;
184 else if (cn_tab == NULL)
185 return ENXIO;
186 else
187 vp = devvp->v_devcookie;
188 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
189 error = VOP_WRITE(vp, uio, flag, p->p_ucred);
190 VOP_UNLOCK(vp, 0);
191 return error;
192 }
193
194 void
195 cnstop(tp, flag)
196 struct tty *tp;
197 int flag;
198 {
199
200 }
201
202 int
203 cnioctl(devvp, cmd, data, flag, p)
204 struct vnode *devvp;
205 u_long cmd;
206 caddr_t data;
207 int flag;
208 struct proc *p;
209 {
210 int error;
211 struct vnode *vp;
212
213 /*
214 * Superuser can always use this to wrest control of console
215 * output from the "virtual" console.
216 */
217 if (cmd == TIOCCONS && constty != NULL) {
218 error = suser(p->p_ucred, (u_short *) NULL);
219 if (error)
220 return (error);
221 constty = NULL;
222 return (0);
223 }
224
225 /*
226 * Redirect the ioctl, if that's appropriate.
227 * Note that strange things can happen, if a program does
228 * ioctls on /dev/console, then the console is redirected
229 * out from under it.
230 */
231 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
232 vp = constty->t_devvp;
233 else if (cn_tab == NULL)
234 return ENXIO;
235 else
236 vp = devvp->v_devcookie;
237
238 return VOP_IOCTL(vp, cmd, data, flag, p->p_ucred, p);
239 }
240
241 /*ARGSUSED*/
242 int
243 cnpoll(devvp, events, p)
244 struct vnode *devvp;
245 int events;
246 struct proc *p;
247 {
248 struct vnode *vp;
249
250 /*
251 * Redirect the poll, if that's appropriate.
252 * I don't want to think of the possible side effects
253 * of console redirection here.
254 */
255 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
256 vp = constty->t_devvp;
257 else if (cn_tab == NULL)
258 return ENXIO;
259 else
260 vp = devvp->v_devcookie;
261
262 return VOP_POLL(vp, events, p);
263 }
264
265 int
266 cngetc()
267 {
268
269 if (cn_tab == NULL)
270 return (0);
271 return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
272 }
273
274 int
275 cngetsn(cp, size)
276 char *cp;
277 int size;
278 {
279 char *lp;
280 int c, len;
281
282 cnpollc(1);
283
284 lp = cp;
285 len = 0;
286 for (;;) {
287 c = cngetc();
288 switch (c) {
289 case '\n':
290 case '\r':
291 printf("\n");
292 *lp++ = '\0';
293 cnpollc(0);
294 return (len);
295 case '\b':
296 case '\177':
297 case '#':
298 if (len) {
299 --len;
300 --lp;
301 printf("\b \b");
302 }
303 continue;
304 case '@':
305 case 'u'&037: /* CTRL-u */
306 len = 0;
307 lp = cp;
308 printf("\n");
309 continue;
310 default:
311 if (len + 1 >= size || c < ' ') {
312 printf("\007");
313 continue;
314 }
315 printf("%c", c);
316 ++len;
317 *lp++ = c;
318 }
319 }
320 }
321
322 void
323 cnputc(c)
324 int c;
325 {
326
327 if (cn_tab == NULL)
328 return;
329
330 if (c) {
331 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
332 if (c == '\n')
333 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
334 }
335 }
336
337 void
338 cnpollc(on)
339 int on;
340 {
341 static int refcount = 0;
342
343 if (cn_tab == NULL)
344 return;
345 if (!on)
346 --refcount;
347 if (refcount == 0)
348 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
349 if (on)
350 ++refcount;
351 }
352
353 void
354 nullcnpollc(dev, on)
355 dev_t dev;
356 int on;
357 {
358
359 }
360
361 void
362 cnbell(pitch, period, volume)
363 u_int pitch, period, volume;
364 {
365
366 if (cn_tab == NULL || cn_tab->cn_bell == NULL)
367 return;
368 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
369 }
370