cons.c revision 1.40.4.1 1 /* $NetBSD: cons.c,v 1.40.4.1 2001/09/07 04:45:22 thorpej 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 struct vnode *cn_devvp; /* vnode for underlying device. */
63
64 int
65 cnopen(devvp, flag, mode, p)
66 struct vnode *devvp;
67 int flag, mode;
68 struct proc *p;
69 {
70 int error;
71 dev_t cndev;
72
73 if (cn_tab == NULL)
74 return (0);
75
76 /* XXXDEVVP */
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 if (devvp->v_rdev == cndev) {
93 /*
94 * This causes cnopen() to be called recursively, which
95 * is generally a bad thing. It is often caused when
96 * dev == 0 and cn_dev has not been set, but was probably
97 * initialised to 0.
98 */
99 panic("cnopen: cn_tab->cn_dev == dev\n");
100 }
101
102 if (cn_devvp == NULLVP) {
103 error = cdevvp(cndev, &cn_devvp);
104 if (error)
105 return (error);
106 }
107 return ((*cdevsw[major(cndev)].d_open)(cn_devvp, flag, mode, p));
108 }
109
110 int
111 cnclose(devvp, flag, mode, p)
112 struct vnode *devvp;
113 int flag, mode;
114 struct proc *p;
115 {
116 struct vnode *vp;
117 dev_t dev;
118
119 if (cn_tab == NULL)
120 return (0);
121
122 /*
123 * If the real console isn't otherwise open, close it.
124 * If it's otherwise open, don't close it, because that'll
125 * screw up others who have it open.
126 */
127 dev = cn_tab->cn_dev;
128 if (cn_devvp != NULLVP) {
129 /* release our reference to real dev's vnode */
130 vrele(cn_devvp);
131 cn_devvp = NULLVP;
132 }
133 if (vfinddev(dev, VCHR, &vp) && vcount(vp))
134 return (0);
135 return ((*cdevsw[major(dev)].d_close)(vp, flag, mode, p));
136 }
137
138 int
139 cnread(devvp, uio, flag)
140 struct vnode *devvp;
141 struct uio *uio;
142 int flag;
143 {
144
145 /*
146 * If we would redirect input, punt. This will keep strange
147 * things from happening to people who are using the real
148 * console. Nothing should be using /dev/console for
149 * input (except a shell in single-user mode, but then,
150 * one wouldn't TIOCCONS then).
151 */
152 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
153 return 0;
154 else if (cn_tab == NULL)
155 return ENXIO;
156
157 return ((*cdevsw[major(cn_tab->cn_dev)].d_read)(cn_devvp, uio, flag));
158 }
159
160 int
161 cnwrite(devvp, uio, flag)
162 struct vnode *devvp;
163 struct uio *uio;
164 int flag;
165 {
166
167 /*
168 * Redirect output, if that's appropriate.
169 * If there's no real console, return ENXIO.
170 */
171 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
172 devvp = constty->t_devvp;
173 else if (cn_tab == NULL)
174 return ENXIO;
175 else
176 devvp = cn_devvp;
177 return ((*cdevsw[major(devvp->v_rdev)].d_write)(devvp, uio, flag));
178 }
179
180 void
181 cnstop(tp, flag)
182 struct tty *tp;
183 int flag;
184 {
185
186 }
187
188 int
189 cnioctl(devvp, cmd, data, flag, p)
190 struct vnode *devvp;
191 u_long cmd;
192 caddr_t data;
193 int flag;
194 struct proc *p;
195 {
196 int error;
197
198 /*
199 * Superuser can always use this to wrest control of console
200 * output from the "virtual" console.
201 */
202 if (cmd == TIOCCONS && constty != NULL) {
203 error = suser(p->p_ucred, (u_short *) NULL);
204 if (error)
205 return (error);
206 constty = NULL;
207 return (0);
208 }
209
210 /*
211 * Redirect the ioctl, if that's appropriate.
212 * Note that strange things can happen, if a program does
213 * ioctls on /dev/console, then the console is redirected
214 * out from under it.
215 */
216 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
217 devvp = constty->t_devvp;
218 else if (cn_tab == NULL)
219 return ENXIO;
220 else
221 devvp = cn_devvp;
222 return ((*cdevsw[major(devvp->v_rdev)].d_ioctl)(devvp, cmd, data,
223 flag, p));
224 }
225
226 /*ARGSUSED*/
227 int
228 cnpoll(devvp, events, p)
229 struct vnode *devvp;
230 int events;
231 struct proc *p;
232 {
233
234 /*
235 * Redirect the poll, if that's appropriate.
236 * I don't want to think of the possible side effects
237 * of console redirection here.
238 */
239 if (constty != NULL && (cn_tab == NULL || cn_tab->cn_pri != CN_REMOTE))
240 devvp = constty->t_devvp;
241 else if (cn_tab == NULL)
242 return ENXIO;
243 else
244 devvp = cn_devvp;
245 return ((*cdevsw[major(devvp->v_rdev)].d_poll)(devvp, events, p));
246 }
247
248 int
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 int
258 cngetsn(cp, size)
259 char *cp;
260 int size;
261 {
262 char *lp;
263 int c, len;
264
265 cnpollc(1);
266
267 lp = cp;
268 len = 0;
269 for (;;) {
270 c = cngetc();
271 switch (c) {
272 case '\n':
273 case '\r':
274 printf("\n");
275 *lp++ = '\0';
276 cnpollc(0);
277 return (len);
278 case '\b':
279 case '\177':
280 case '#':
281 if (len) {
282 --len;
283 --lp;
284 printf("\b \b");
285 }
286 continue;
287 case '@':
288 case 'u'&037: /* CTRL-u */
289 len = 0;
290 lp = cp;
291 printf("\n");
292 continue;
293 default:
294 if (len + 1 >= size || c < ' ') {
295 printf("\007");
296 continue;
297 }
298 printf("%c", c);
299 ++len;
300 *lp++ = c;
301 }
302 }
303 }
304
305 void
306 cnputc(c)
307 int c;
308 {
309
310 if (cn_tab == NULL)
311 return;
312
313 if (c) {
314 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
315 if (c == '\n')
316 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
317 }
318 }
319
320 void
321 cnpollc(on)
322 int on;
323 {
324 static int refcount = 0;
325
326 if (cn_tab == NULL)
327 return;
328 if (!on)
329 --refcount;
330 if (refcount == 0)
331 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
332 if (on)
333 ++refcount;
334 }
335
336 void
337 nullcnpollc(dev, on)
338 dev_t dev;
339 int on;
340 {
341
342 }
343
344 void
345 cnbell(pitch, period, volume)
346 u_int pitch, period, volume;
347 {
348
349 if (cn_tab == NULL || cn_tab->cn_bell == NULL)
350 return;
351 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
352 }
353