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$
40 */
41
42 #include "opt_devfs.h"
43
44 #include <sys/param.h>
45 #ifdef DEVFS
46 #include <sys/devfsext.h>
47 #endif /*DEVFS*/
48 #include <sys/systm.h>
49 #include <sys/conf.h>
50 #include <sys/kernel.h>
51 #include <sys/reboot.h>
52 #include <sys/sysctl.h>
53 #include <sys/proc.h>
54 #include <sys/tty.h>
55 #include <sys/uio.h>
56
57 #include <machine/cpu.h>
58 #include <machine/cons.h>
59
60 static d_open_t cnopen;
61 static d_close_t cnclose;
62 static d_read_t cnread;
63 static d_write_t cnwrite;
64 static d_ioctl_t cnioctl;
65 static d_poll_t cnpoll;
66
67 #define CDEV_MAJOR 0
68 static struct cdevsw cn_cdevsw = {
69 cnopen, cnclose, cnread, cnwrite,
70 cnioctl, nullstop, nullreset, nodevtotty,
71 cnpoll, nommap, NULL, "console",
72 NULL, -1, nodump, nopsize,
73 D_TTY,
74 };
75
76 static dev_t cn_dev_t; /* seems to be never really used */
77 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
78 &cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
79
80 static int cn_mute;
81
82 int cons_unavail = 0; /* XXX:
83 * physical console not available for
84 * input (i.e., it is in graphics mode)
85 */
86
87 static u_char cn_is_open; /* nonzero if logical console is open */
88 static int openmode, openflag; /* how /dev/console was openned */
89 static u_char cn_phys_is_open; /* nonzero if physical device is open */
90 static d_close_t *cn_phys_close; /* physical device close function */
91 static d_open_t *cn_phys_open; /* physical device open function */
92 static struct consdev *cn_tab; /* physical console device info */
93 static struct tty *cn_tp; /* physical console tty struct */
94 #ifdef DEVFS
95 static void *cn_devfs_token; /* represents the devfs entry */
96 #endif /* DEVFS */
97
98 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL);
99
100 void
101 cninit()
102 {
103 struct consdev *best_cp, *cp;
104 struct consdev **list;
105
106 /*
107 * Find the first console with the highest priority.
108 */
109 best_cp = NULL;
110 list = (struct consdev **)cons_set.ls_items;
111 while ((cp = *list++) != NULL) {
112 if (cp->cn_probe == NULL)
113 continue;
114 (*cp->cn_probe)(cp);
115 if (cp->cn_pri > CN_DEAD &&
116 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
117 best_cp = cp;
118 }
119
120 /*
121 * Check if we should mute the console (for security reasons perhaps)
122 * It can be changes dynamically using sysctl kern.consmute
123 * once we are up and going.
124 *
125 */
126 cn_mute = ((boothowto & (RB_MUTE
127 |RB_SINGLE
128 |RB_VERBOSE
129 |RB_ASKNAME
130 |RB_CONFIG)) == RB_MUTE);
131
132 /*
133 * If no console, give up.
134 */
135 if (best_cp == NULL) {
136 cn_tab = best_cp;
137 return;
138 }
139
140 /*
141 * Initialize console, then attach to it. This ordering allows
142 * debugging using the previous console, if any.
143 * XXX if there was a previous console, then its driver should
144 * be informed when we forget about it.
145 */
146 (*best_cp->cn_init)(best_cp);
147 cn_tab = best_cp;
148 }
149
150 void
151 cninit_finish()
152 {
153 struct cdevsw *cdp;
154
155 if ((cn_tab == NULL) || cn_mute)
156 return;
157
158 /*
159 * Hook the open and close functions.
160 */
161 cdp = cdevsw[major(cn_tab->cn_dev)];
162 cn_phys_close = cdp->d_close;
163 cdp->d_close = cnclose;
164 cn_phys_open = cdp->d_open;
165 cdp->d_open = cnopen;
166 cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
167 cn_dev_t = cn_tp->t_dev;
168 }
169
170 static void
171 cnuninit(void)
172 {
173 struct cdevsw *cdp;
174
175 if (cn_tab == NULL)
176 return;
177
178 /*
179 * Unhook the open and close functions.
180 */
181 cdp = cdevsw[major(cn_tab->cn_dev)];
182 cdp->d_close = cn_phys_close;
183 cn_phys_close = NULL;
184 cdp->d_open = cn_phys_open;
185 cn_phys_open = NULL;
186 cn_tp = NULL;
187 cn_dev_t = 0;
188 }
189
190 /*
191 * User has changed the state of the console muting.
192 * This may require us to open or close the device in question.
193 */
194 static int
195 sysctl_kern_consmute SYSCTL_HANDLER_ARGS
196 {
197 int error;
198 int ocn_mute;
199
200 ocn_mute = cn_mute;
201 error = sysctl_handle_int(oidp, &cn_mute, 0, req);
202 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
203 if(ocn_mute && !cn_mute) {
204 /*
205 * going from muted to unmuted.. open the physical dev
206 * if the console has been openned
207 */
208 cninit_finish();
209 if(cn_is_open)
210 /* XXX curproc is not what we want really */
211 error = cnopen(cn_dev_t, openflag,
212 openmode, curproc);
213 /* if it failed, back it out */
214 if ( error != 0) cnuninit();
215 } else if (!ocn_mute && cn_mute) {
216 /*
217 * going from unmuted to muted.. close the physical dev
218 * if it's only open via /dev/console
219 */
220 if(cn_is_open)
221 error = cnclose(cn_dev_t, openflag,
222 openmode, curproc);
223 if ( error == 0) cnuninit();
224 }
225 if (error != 0) {
226 /*
227 * back out the change if there was an error
228 */
229 cn_mute = ocn_mute;
230 }
231 }
232 return (error);
233 }
234
235 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
236 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
237
238 static int
239 cnopen(dev, flag, mode, p)
240 dev_t dev;
241 int flag, mode;
242 struct proc *p;
243 {
244 dev_t cndev, physdev;
245 int retval = 0;
246
247 if (cn_tab == NULL)
248 return (0);
249 cndev = cn_tab->cn_dev;
250 physdev = (major(dev) == major(cndev) ? dev : cndev);
251 /*
252 * If mute is active, then non console opens don't get here
253 * so we don't need to check for that. They
254 * bypass this and go straight to the device.
255 */
256 if(!cn_mute)
257 retval = (*cn_phys_open)(physdev, flag, mode, p);
258 if (retval == 0) {
259 /*
260 * check if we openned it via /dev/console or
261 * via the physical entry (e.g. /dev/sio0).
262 */
263 if (dev == cndev)
264 cn_phys_is_open = 1;
265 else if (physdev == cndev) {
266 openmode = mode;
267 openflag = flag;
268 cn_is_open = 1;
269 }
270 }
271 return (retval);
272 }
273
274 static int
275 cnclose(dev, flag, mode, p)
276 dev_t dev;
277 int flag, mode;
278 struct proc *p;
279 {
280 dev_t cndev;
281
282 if (cn_tab == NULL)
283 return (0);
284 cndev = cn_tab->cn_dev;
285 /*
286 * act appropriatly depending on whether it's /dev/console
287 * or the pysical device (e.g. /dev/sio) that's being closed.
288 * in either case, don't actually close the device unless
289 * both are closed.
290 */
291 if (dev == cndev) {
292 /* the physical device is about to be closed */
293 cn_phys_is_open = 0;
294 if (cn_is_open) {
295 if (cn_tp) {
296 /* perform a ttyhalfclose() */
297 /* reset session and proc group */
298 cn_tp->t_pgrp = NULL;
299 cn_tp->t_session = NULL;
300 }
301 return (0);
302 }
303 } else if (major(dev) != major(cndev)) {
304 /* the logical console is about to be closed */
305 cn_is_open = 0;
306 if (cn_phys_is_open)
307 return (0);
308 dev = cndev;
309 }
310 if(cn_phys_close)
311 return ((*cn_phys_close)(dev, flag, mode, p));
312 return (0);
313 }
314
315 static int
316 cnread(dev, uio, flag)
317 dev_t dev;
318 struct uio *uio;
319 int flag;
320 {
321 if ((cn_tab == NULL) || cn_mute)
322 return (0);
323 dev = cn_tab->cn_dev;
324 return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
325 }
326
327 static int
328 cnwrite(dev, uio, flag)
329 dev_t dev;
330 struct uio *uio;
331 int flag;
332 {
333 if ((cn_tab == NULL) || cn_mute) {
334 uio->uio_resid = 0; /* dump the data */
335 return (0);
336 }
337 if (constty)
338 dev = constty->t_dev;
339 else
340 dev = cn_tab->cn_dev;
341 return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
342 }
343
344 static int
345 cnioctl(dev, cmd, data, flag, p)
346 dev_t dev;
347 u_long cmd;
348 caddr_t data;
349 int flag;
350 struct proc *p;
351 {
352 int error;
353
354 if ((cn_tab == NULL) || cn_mute)
355 return (0);
356 /*
357 * Superuser can always use this to wrest control of console
358 * output from the "virtual" console.
359 */
360 if (cmd == TIOCCONS && constty) {
361 error = suser(p->p_ucred, (u_short *) NULL);
362 if (error)
363 return (error);
364 constty = NULL;
365 return (0);
366 }
367 dev = cn_tab->cn_dev;
368 return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
369 }
370
371 static int
372 cnpoll(dev, events, p)
373 dev_t dev;
374 int events;
375 struct proc *p;
376 {
377 if ((cn_tab == NULL) || cn_mute)
378 return (1);
379
380 dev = cn_tab->cn_dev;
381
382 return ((*cdevsw[major(dev)]->d_poll)(dev, events, p));
383 }
384
385 int
386 cngetc()
387 {
388 int c;
389 if ((cn_tab == NULL) || cn_mute)
390 return (-1);
391 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
392 if (c == '\r') c = '\n'; /* console input is always ICRNL */
393 return (c);
394 }
395
396 int
397 cncheckc()
398 {
399 if ((cn_tab == NULL) || cn_mute)
400 return (-1);
401 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
402 }
403
404 void
405 cnputc(c)
406 register int c;
407 {
408 if ((cn_tab == NULL) || cn_mute)
409 return;
410 if (c) {
411 if (c == '\n')
412 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
413 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
414 }
415 }
416
417 static cn_devsw_installed = 0;
418
419 static void
420 cn_drvinit(void *unused)
421 {
422 dev_t dev;
423
424 if( ! cn_devsw_installed ) {
425 dev = makedev(CDEV_MAJOR,0);
426 cdevsw_add(&dev,&cn_cdevsw,NULL);
427 cn_devsw_installed = 1;
428 #ifdef DEVFS
429 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR,
430 UID_ROOT, GID_WHEEL, 0600,
431 "console");
432 #endif
433 }
434 }
435
436 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
437
438
Cache object: 6b58203e1c759514891b4d21f5b2bad4
|