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