FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/cons.c
1 /*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
39 * $FreeBSD: src/sys/i386/i386/cons.c,v 1.49.2.2 1999/09/05 08:11:04 peter Exp $
40 */
41
42 #include <sys/param.h>
43 #ifdef DEVFS
44 #include <sys/devfsext.h>
45 #endif /*DEVFS*/
46 #include <sys/systm.h>
47 #include <sys/conf.h>
48 #include <sys/kernel.h>
49 #include <sys/reboot.h>
50 #include <sys/sysctl.h>
51 #include <sys/proc.h>
52 #include <sys/tty.h>
53
54 #include <machine/cpu.h>
55 #include <machine/cons.h>
56
57 /* XXX this should be config(8)ed. */
58 #include "sc.h"
59 #include "vt.h"
60 #include "sio.h"
61 static struct consdev constab[] = {
62 #if NSC > 0
63 { sccnprobe, sccninit, sccngetc, sccncheckc, sccnputc },
64 #endif
65 #if NVT > 0
66 { pccnprobe, pccninit, pccngetc, pccncheckc, pccnputc },
67 #endif
68 #if NSIO > 0
69 { siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc },
70 #endif
71 { 0 },
72 };
73
74 static d_open_t cnopen;
75 static d_close_t cnclose;
76 static d_read_t cnread;
77 static d_write_t cnwrite;
78 static d_ioctl_t cnioctl;
79 static d_select_t cnselect;
80
81 #define CDEV_MAJOR 0
82 static struct cdevsw cn_cdevsw =
83 { cnopen, cnclose, cnread, cnwrite, /**/
84 cnioctl, nullstop, nullreset, nodevtotty,/* console */
85 cnselect, nommap, NULL, "console", NULL, -1 };
86
87 struct tty *constty = 0; /* virtual console output device */
88
89 static dev_t cn_dev_t; /* seems to be never really used */
90 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLTYPE_OPAQUE|CTLFLAG_RD,
91 &cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
92
93 static int cn_mute;
94
95 int cons_unavail = 0; /* XXX:
96 * physical console not available for
97 * input (i.e., it is in graphics mode)
98 */
99
100 static u_char cn_is_open; /* nonzero if logical console is open */
101 static int openmode, openflag; /* how /dev/console was openned */
102 static u_char cn_phys_is_open; /* nonzero if physical device is open */
103 static d_close_t *cn_phys_close; /* physical device close function */
104 static d_open_t *cn_phys_open; /* physical device open function */
105 static struct consdev *cn_tab; /* physical console device info */
106 static struct tty *cn_tp; /* physical console tty struct */
107 #ifdef DEVFS
108 static void *cn_devfs_token; /* represents the devfs entry */
109 #endif /* DEVFS */
110
111 void
112 cninit()
113 {
114 struct consdev *best_cp, *cp;
115
116 /*
117 * Find the first console with the highest priority.
118 */
119 best_cp = NULL;
120 for (cp = constab; cp->cn_probe; cp++) {
121 (*cp->cn_probe)(cp);
122 if (cp->cn_pri > CN_DEAD &&
123 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
124 best_cp = cp;
125 }
126
127 /*
128 * Check if we should mute the console (for security reasons perhaps)
129 * It can be changes dynamically using sysctl kern.consmute
130 * once we are up and going.
131 *
132 */
133 cn_mute = ((boothowto & (RB_MUTE
134 |RB_SINGLE
135 |RB_VERBOSE
136 |RB_ASKNAME
137 |RB_CONFIG)) == RB_MUTE);
138
139 /*
140 * If no console, give up.
141 */
142 if (best_cp == NULL) {
143 cn_tab = best_cp;
144 return;
145 }
146
147 /*
148 * Initialize console, then attach to it. This ordering allows
149 * debugging using the previous console, if any.
150 * XXX if there was a previous console, then its driver should
151 * be informed when we forget about it.
152 */
153 (*best_cp->cn_init)(best_cp);
154 cn_tab = best_cp;
155 }
156
157 void
158 cninit_finish()
159 {
160 struct cdevsw *cdp;
161
162 if ((cn_tab == NULL) || cn_mute)
163 return;
164
165 /*
166 * Hook the open and close functions.
167 */
168 cdp = cdevsw[major(cn_tab->cn_dev)];
169 cn_phys_close = cdp->d_close;
170 cdp->d_close = cnclose;
171 cn_phys_open = cdp->d_open;
172 cdp->d_open = cnopen;
173 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
174 cn_dev_t = cn_tp->t_dev;
175 }
176
177 static void
178 cnuninit(void)
179 {
180 struct cdevsw *cdp;
181
182 if (cn_tab == NULL)
183 return;
184
185 /*
186 * Unhook the open and close functions.
187 */
188 cdp = cdevsw[major(cn_tab->cn_dev)];
189 cdp->d_close = cn_phys_close;
190 cn_phys_close = NULL;
191 cdp->d_open = cn_phys_open;
192 cn_phys_open = NULL;
193 cn_tp = NULL;
194 cn_dev_t = 0;
195 }
196
197 /*
198 * User has changed the state of the console muting.
199 * This may require us to open or close the device in question.
200 */
201 static int
202 sysctl_kern_consmute SYSCTL_HANDLER_ARGS
203 {
204 int error;
205 int ocn_mute;
206
207 ocn_mute = cn_mute;
208 error = sysctl_handle_int(oidp, &cn_mute, 0, req);
209 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
210 if(ocn_mute && !cn_mute) {
211 /*
212 * going from muted to unmuted.. open the physical dev
213 * if the console has been openned
214 */
215 cninit_finish();
216 if(cn_is_open)
217 /* XXX curproc is not what we want really */
218 error = cnopen(cn_dev_t, openflag,
219 openmode, curproc);
220 /* if it failed, back it out */
221 if ( error != 0) cnuninit();
222 } else if (!ocn_mute && cn_mute) {
223 /*
224 * going from unmuted to muted.. close the physical dev
225 * if it's only open via /dev/console
226 */
227 if(cn_is_open)
228 error = cnclose(cn_dev_t, openflag,
229 openmode, curproc);
230 if ( error == 0) cnuninit();
231 }
232 if (error != 0) {
233 /*
234 * back out the change if there was an error
235 */
236 cn_mute = ocn_mute;
237 }
238 }
239 return (error);
240 }
241
242 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
243 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
244
245 static int
246 cnopen(dev, flag, mode, p)
247 dev_t dev;
248 int flag, mode;
249 struct proc *p;
250 {
251 dev_t cndev, physdev;
252 int retval = 0;
253
254 if (cn_tab == NULL)
255 return (0);
256 cndev = cn_tab->cn_dev;
257 physdev = (major(dev) == major(cndev) ? dev : cndev);
258 /*
259 * If mute is active, then non console opens don't get here
260 * so we don't need to check for that. They
261 * bypass this and go straight to the device.
262 */
263 if(!cn_mute)
264 retval = (*cn_phys_open)(physdev, flag, mode, p);
265 if (retval == 0) {
266 /*
267 * check if we openned it via /dev/console or
268 * via the physical entry (e.g. /dev/sio0).
269 */
270 if (dev == cndev)
271 cn_phys_is_open = 1;
272 else if (physdev == cndev) {
273 openmode = mode;
274 openflag = flag;
275 cn_is_open = 1;
276 }
277 }
278 return (retval);
279 }
280
281 static int
282 cnclose(dev, flag, mode, p)
283 dev_t dev;
284 int flag, mode;
285 struct proc *p;
286 {
287 dev_t cndev;
288
289 if (cn_tab == NULL)
290 return (0);
291 cndev = cn_tab->cn_dev;
292 /*
293 * act appropriatly depending on whether it's /dev/console
294 * or the pysical device (e.g. /dev/sio) that's being closed.
295 * in either case, don't actually close the device unless
296 * both are closed.
297 */
298 if (dev == cndev) {
299 /* the physical device is about to be closed */
300 cn_phys_is_open = 0;
301 if (cn_is_open) {
302 if (cn_tp) {
303 /* perform a ttyhalfclose() */
304 /* reset session and proc group */
305 cn_tp->t_pgrp = NULL;
306 cn_tp->t_session = NULL;
307 }
308 return (0);
309 }
310 } else if (major(dev) != major(cndev)) {
311 /* the logical console is about to be closed */
312 cn_is_open = 0;
313 if (cn_phys_is_open)
314 return (0);
315 dev = cndev;
316 }
317 if(cn_phys_close)
318 return ((*cn_phys_close)(dev, flag, mode, p));
319 return (0);
320 }
321
322 static int
323 cnread(dev, uio, flag)
324 dev_t dev;
325 struct uio *uio;
326 int flag;
327 {
328 if ((cn_tab == NULL) || cn_mute)
329 return (0);
330 dev = cn_tab->cn_dev;
331 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
332 }
333
334 static int
335 cnwrite(dev, uio, flag)
336 dev_t dev;
337 struct uio *uio;
338 int flag;
339 {
340 if ((cn_tab == NULL) || cn_mute) {
341 uio->uio_resid = 0; /* dump the data */
342 return (0);
343 }
344 if (constty)
345 dev = constty->t_dev;
346 else
347 dev = cn_tab->cn_dev;
348 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
349 }
350
351 static int
352 cnioctl(dev, cmd, data, flag, p)
353 dev_t dev;
354 int cmd;
355 caddr_t data;
356 int flag;
357 struct proc *p;
358 {
359 int error;
360
361 if ((cn_tab == NULL) || cn_mute)
362 return (0);
363 /*
364 * Superuser can always use this to wrest control of console
365 * output from the "virtual" console.
366 */
367 if (cmd == TIOCCONS && constty) {
368 error = suser(p->p_ucred, (u_short *) NULL);
369 if (error)
370 return (error);
371 constty = NULL;
372 return (0);
373 }
374 dev = cn_tab->cn_dev;
375 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
376 }
377
378 static int
379 cnselect(dev, rw, p)
380 dev_t dev;
381 int rw;
382 struct proc *p;
383 {
384 if ((cn_tab == NULL) || cn_mute)
385 return (1);
386
387 dev = cn_tab->cn_dev;
388
389 return ((*cdevsw[major(dev)]->d_select)(dev, rw, p));
390 }
391
392 int
393 cngetc()
394 {
395 int c;
396 if ((cn_tab == NULL) || cn_mute)
397 return (-1);
398 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
399 if (c == '\r') c = '\n'; /* console input is always ICRNL */
400 return (c);
401 }
402
403 int
404 cncheckc()
405 {
406 if ((cn_tab == NULL) || cn_mute)
407 return (-1);
408 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
409 }
410
411 void
412 cnputc(c)
413 register int c;
414 {
415 if ((cn_tab == NULL) || cn_mute)
416 return;
417 if (c) {
418 if (c == '\n')
419 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
420 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
421 }
422 }
423
424 static cn_devsw_installed = 0;
425
426 static void
427 cn_drvinit(void *unused)
428 {
429 dev_t dev;
430
431 if( ! cn_devsw_installed ) {
432 dev = makedev(CDEV_MAJOR,0);
433 cdevsw_add(&dev,&cn_cdevsw,NULL);
434 cn_devsw_installed = 1;
435 #ifdef DEVFS
436 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR,
437 UID_ROOT, GID_WHEEL, 0600,
438 "console");
439 #endif
440 }
441 }
442
443 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
444
445
Cache object: aeff8e027a7d1a60225ee4cc7ad57db1
|