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