Deleted Added
sdiff udiff text old ( 62573 ) new ( 67893 )
full compact
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: head/sys/kern/tty_cons.c 67893 2000-10-29 16:06:56Z phk $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/conf.h>
45#include <sys/cons.h>
46#include <sys/kernel.h>
47#include <sys/reboot.h>
48#include <sys/sysctl.h>
49#include <sys/tty.h>
50#include <sys/uio.h>
51
52#include <machine/cpu.h>
53
54static d_open_t cnopen;
55static d_close_t cnclose;
56static d_read_t cnread;
57static d_write_t cnwrite;
58static d_ioctl_t cnioctl;
59static d_poll_t cnpoll;
60
61#define CDEV_MAJOR 0
62static struct cdevsw cn_cdevsw = {
63 /* open */ cnopen,
64 /* close */ cnclose,
65 /* read */ cnread,
66 /* write */ cnwrite,
67 /* ioctl */ cnioctl,
68 /* poll */ cnpoll,
69 /* mmap */ nommap,
70 /* strategy */ nostrategy,
71 /* name */ "console",
72 /* maj */ CDEV_MAJOR,
73 /* dump */ nodump,
74 /* psize */ nopsize,
75 /* flags */ D_TTY,
76 /* bmaj */ -1
77};
78
79static dev_t cn_dev_t; /* seems to be never really used */
80static udev_t cn_udev_t;
81SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
82 &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
83
84static int cn_mute;
85
86int cons_unavail = 0; /* XXX:
87 * physical console not available for
88 * input (i.e., it is in graphics mode)
89 */
90
91static u_char cn_is_open; /* nonzero if logical console is open */
92static int openmode, openflag; /* how /dev/console was openned */
93static dev_t cn_devfsdev; /* represents the device private info */
94static u_char cn_phys_is_open; /* nonzero if physical device is open */
95static d_close_t *cn_phys_close; /* physical device close function */
96static d_open_t *cn_phys_open; /* physical device open function */
97 struct consdev *cn_tab; /* physical console device info */
98
99CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
100
101void
102cninit()
103{
104 struct consdev *best_cp, *cp, **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 if (cn_tab != NULL && cn_tab->cn_term != NULL)
137 (*cn_tab->cn_term)(cn_tab);
138 cn_tab = best_cp;
139 return;
140 }
141
142 /*
143 * Initialize console, then attach to it. This ordering allows
144 * debugging using the previous console, if any.
145 */
146 (*best_cp->cn_init)(best_cp);
147 if (cn_tab != NULL && cn_tab != best_cp) {
148 /* Turn off the previous console. */
149 if (cn_tab->cn_term != NULL)
150 (*cn_tab->cn_term)(cn_tab);
151 }
152 cn_tab = best_cp;
153}
154
155void
156cninit_finish()
157{
158 struct cdevsw *cdp;
159
160 if ((cn_tab == NULL) || cn_mute)
161 return;
162
163 /*
164 * Hook the open and close functions.
165 */
166 cdp = devsw(cn_tab->cn_dev);
167 if (cdp != NULL) {
168 cn_phys_close = cdp->d_close;
169 cdp->d_close = cnclose;
170 cn_phys_open = cdp->d_open;
171 cdp->d_open = cnopen;
172 }
173 cn_dev_t = cn_tab->cn_dev;
174 cn_udev_t = dev2udev(cn_dev_t);
175}
176
177static void
178cnuninit(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 = devsw(cn_tab->cn_dev);
189 if (cdp != NULL) {
190 cdp->d_close = cn_phys_close;
191 cdp->d_open = cn_phys_open;
192 }
193 cn_phys_close = NULL;
194 cn_phys_open = NULL;
195 cn_dev_t = NODEV;
196 cn_udev_t = NOUDEV;
197}
198
199/*
200 * User has changed the state of the console muting.
201 * This may require us to open or close the device in question.
202 */
203static int
204sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
205{
206 int error;
207 int ocn_mute;
208
209 ocn_mute = cn_mute;
210 error = sysctl_handle_int(oidp, &cn_mute, 0, req);
211 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
212 if(ocn_mute && !cn_mute) {
213 /*
214 * going from muted to unmuted.. open the physical dev
215 * if the console has been openned
216 */
217 cninit_finish();
218 if(cn_is_open)
219 /* XXX curproc is not what we want really */
220 error = cnopen(cn_dev_t, openflag,
221 openmode, curproc);
222 /* if it failed, back it out */
223 if ( error != 0) cnuninit();
224 } else if (!ocn_mute && cn_mute) {
225 /*
226 * going from unmuted to muted.. close the physical dev
227 * if it's only open via /dev/console
228 */
229 if(cn_is_open)
230 error = cnclose(cn_dev_t, openflag,
231 openmode, curproc);
232 if ( error == 0) cnuninit();
233 }
234 if (error != 0) {
235 /*
236 * back out the change if there was an error
237 */
238 cn_mute = ocn_mute;
239 }
240 }
241 return (error);
242}
243
244SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
245 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
246
247static int
248cnopen(dev, flag, mode, p)
249 dev_t dev;
250 int flag, mode;
251 struct proc *p;
252{
253 dev_t cndev, physdev;
254 int retval = 0;
255
256 if (cn_tab == NULL || cn_phys_open == NULL)
257 return (0);
258 cndev = cn_tab->cn_dev;
259 physdev = (major(dev) == major(cndev) ? dev : cndev);
260 /*
261 * If mute is active, then non console opens don't get here
262 * so we don't need to check for that. They
263 * bypass this and go straight to the device.
264 */
265 if(!cn_mute)
266 retval = (*cn_phys_open)(physdev, flag, mode, p);
267 if (retval == 0) {
268 /*
269 * check if we openned it via /dev/console or
270 * via the physical entry (e.g. /dev/sio0).
271 */
272 if (dev == cndev)
273 cn_phys_is_open = 1;
274 else if (physdev == cndev) {
275 openmode = mode;
276 openflag = flag;
277 cn_is_open = 1;
278 }
279 dev->si_tty = physdev->si_tty;
280 }
281 return (retval);
282}
283
284static int
285cnclose(dev, flag, mode, p)
286 dev_t dev;
287 int flag, mode;
288 struct proc *p;
289{
290 dev_t cndev;
291 struct tty *cn_tp;
292
293 if (cn_tab == NULL || cn_phys_open == NULL)
294 return (0);
295 cndev = cn_tab->cn_dev;
296 cn_tp = cndev->si_tty;
297 /*
298 * act appropriatly depending on whether it's /dev/console
299 * or the pysical device (e.g. /dev/sio) that's being closed.
300 * in either case, don't actually close the device unless
301 * both are closed.
302 */
303 if (dev == cndev) {
304 /* the physical device is about to be closed */
305 cn_phys_is_open = 0;
306 if (cn_is_open) {
307 if (cn_tp) {
308 /* perform a ttyhalfclose() */
309 /* reset session and proc group */
310 cn_tp->t_pgrp = NULL;
311 cn_tp->t_session = NULL;
312 }
313 return (0);
314 }
315 } else if (major(dev) != major(cndev)) {
316 /* the logical console is about to be closed */
317 cn_is_open = 0;
318 if (cn_phys_is_open)
319 return (0);
320 dev = cndev;
321 }
322 if(cn_phys_close)
323 return ((*cn_phys_close)(dev, flag, mode, p));
324 return (0);
325}
326
327static int
328cnread(dev, uio, flag)
329 dev_t dev;
330 struct uio *uio;
331 int flag;
332{
333
334 if (cn_tab == NULL || cn_phys_open == NULL)
335 return (0);
336 dev = cn_tab->cn_dev;
337 return ((*devsw(dev)->d_read)(dev, uio, flag));
338}
339
340static int
341cnwrite(dev, uio, flag)
342 dev_t dev;
343 struct uio *uio;
344 int flag;
345{
346
347 if (cn_tab == NULL || cn_phys_open == NULL) {
348 uio->uio_resid = 0; /* dump the data */
349 return (0);
350 }
351 if (constty)
352 dev = constty->t_dev;
353 else
354 dev = cn_tab->cn_dev;
355 return ((*devsw(dev)->d_write)(dev, uio, flag));
356}
357
358static int
359cnioctl(dev, cmd, data, flag, p)
360 dev_t dev;
361 u_long cmd;
362 caddr_t data;
363 int flag;
364 struct proc *p;
365{
366 int error;
367
368 if (cn_tab == NULL || cn_phys_open == NULL)
369 return (0);
370 /*
371 * Superuser can always use this to wrest control of console
372 * output from the "virtual" console.
373 */
374 if (cmd == TIOCCONS && constty) {
375 error = suser(p);
376 if (error)
377 return (error);
378 constty = NULL;
379 return (0);
380 }
381 dev = cn_tab->cn_dev;
382 return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p));
383}
384
385static int
386cnpoll(dev, events, p)
387 dev_t dev;
388 int events;
389 struct proc *p;
390{
391 if ((cn_tab == NULL) || cn_mute)
392 return (1);
393
394 dev = cn_tab->cn_dev;
395
396 return ((*devsw(dev)->d_poll)(dev, events, p));
397}
398
399int
400cngetc()
401{
402 int c;
403 if ((cn_tab == NULL) || cn_mute)
404 return (-1);
405 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
406 if (c == '\r') c = '\n'; /* console input is always ICRNL */
407 return (c);
408}
409
410int
411cncheckc()
412{
413 if ((cn_tab == NULL) || cn_mute)
414 return (-1);
415 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
416}
417
418void
419cnputc(c)
420 register int c;
421{
422 if ((cn_tab == NULL) || cn_mute)
423 return;
424 if (c) {
425 if (c == '\n')
426 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
427 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
428 }
429}
430
431void
432cndbctl(on)
433 int on;
434{
435 static int refcount;
436
437 if (cn_tab == NULL)
438 return;
439 if (!on)
440 refcount--;
441 if (refcount == 0 && cn_tab->cn_dbctl != NULL)
442 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
443 if (on)
444 refcount++;
445}
446
447static void
448cn_drvinit(void *unused)
449{
450
451 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
452 "console");
453}
454
455SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)