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