2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1991 The Regents of the University of California.
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
38 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
39 * $FreeBSD: src/sys/kern/tty_cons.c,v 1.81.2.4 2001/12/17 18:44:41 guido Exp $
40 * $DragonFly: src/sys/kern/tty_cons.c,v 1.14 2004/09/13 16:22:36 dillon Exp $
45 #include <sys/param.h>
46 #include <sys/systm.h>
49 #include <sys/kernel.h>
51 #include <sys/reboot.h>
52 #include <sys/sysctl.h>
55 #include <sys/msgport.h>
56 #include <sys/msgport2.h>
57 #include <sys/device.h>
61 #include <machine/cpu.h>
63 static int cnopen(struct cdevmsg_open *msg);
64 static int cnclose(struct cdevmsg_close *msg);
65 static int cnread(struct cdevmsg_read *msg);
66 static int cnwrite(struct cdevmsg_write *msg);
67 static int cnioctl(struct cdevmsg_ioctl *msg);
68 static int cnpoll(struct cdevmsg_poll *msg);
69 static int cnkqfilter(struct cdevmsg_kqfilter *msg);
71 static int console_putport(lwkt_port_t port, lwkt_msg_t lmsg);
72 static int console_interceptport(lwkt_port_t port, lwkt_msg_t lmsg);
74 static struct lwkt_port cn_port; /* console device port */
75 static struct lwkt_port cn_iport; /* intercept port */
78 static struct cdevsw cn_cdevsw = {
81 /* flags */ D_TTY | D_KQFILTER,
86 static dev_t cn_dev_t;
87 static udev_t cn_udev_t;
88 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
89 &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
93 int cons_unavail = 0; /* XXX:
94 * physical console not available for
95 * input (i.e., it is in graphics mode)
98 static u_char cn_is_open; /* nonzero if logical console is open */
99 static int openmode, openflag; /* how /dev/console was openned */
100 static dev_t cn_devfsdev; /* represents the device private info */
101 static u_char cn_phys_is_open; /* nonzero if physical device is open */
102 struct consdev *cn_tab; /* physical console device info */
103 static u_char console_pausing; /* pause after each line during probe */
104 static char *console_pausestr=
105 "<pause; press any key to proceed to next line or '.' to end pause mode>";
107 static lwkt_port_t cn_fwd_port;
109 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
110 SET_DECLARE(cons_set, struct consdev);
115 struct consdev *best_cp, *cp, **list;
120 lwkt_initport(&cn_port, NULL);
121 cn_port.mp_putport = console_putport;
122 lwkt_initport(&cn_iport, NULL);
123 cn_iport.mp_putport = console_interceptport;
126 * Find the first console with the highest priority.
129 SET_FOREACH(list, cons_set) {
131 if (cp->cn_probe == NULL)
134 if (cp->cn_pri > CN_DEAD &&
135 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
140 * Check if we should mute the console (for security reasons perhaps)
141 * It can be changes dynamically using sysctl kern.consmute
142 * once we are up and going.
145 cn_mute = ((boothowto & (RB_MUTE
149 |RB_CONFIG)) == RB_MUTE);
152 * If no console, give up.
154 if (best_cp == NULL) {
155 if (cn_tab != NULL && cn_tab->cn_term != NULL)
156 (*cn_tab->cn_term)(cn_tab);
162 * Initialize console, then attach to it. This ordering allows
163 * debugging using the previous console, if any.
165 (*best_cp->cn_init)(best_cp);
166 if (cn_tab != NULL && cn_tab != best_cp) {
167 /* Turn off the previous console. */
168 if (cn_tab->cn_term != NULL)
169 (*cn_tab->cn_term)(cn_tab);
171 if (boothowto & RB_PAUSE)
177 * Hook the open and close functions on the selected device.
182 if ((cn_tab == NULL) || cn_mute)
186 * Hook the open and close functions. XXX bad hack.
188 if (dev_is_good(cn_tab->cn_dev))
189 cn_fwd_port = cdevsw_dev_override(cn_tab->cn_dev, &cn_iport);
190 cn_dev_t = cn_tab->cn_dev;
191 cn_udev_t = dev2udev(cn_dev_t);
202 * Unhook the open and close functions. XXX bad hack
205 cdevsw_dev_override(cn_tab->cn_dev, cn_fwd_port);
212 * User has changed the state of the console muting.
213 * This may require us to open or close the device in question.
216 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
222 error = sysctl_handle_int(oidp, &cn_mute, 0, req);
223 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
224 if(ocn_mute && !cn_mute) {
226 * going from muted to unmuted.. open the physical dev
227 * if the console has been openned
231 /* XXX curproc is not what we want really */
232 error = dev_dopen(cn_dev_t, openflag,
233 openmode, curthread);
235 /* if it failed, back it out */
236 if ( error != 0) cnuninit();
237 } else if (!ocn_mute && cn_mute) {
239 * going from unmuted to muted.. close the physical dev
240 * if it's only open via /dev/console
243 error = dev_dclose(cn_dev_t, openflag,
244 openmode, curthread);
251 * back out the change if there was an error
259 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
260 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
263 * We intercept the OPEN and CLOSE calls on the original device, and
264 * forward the rest through.
267 console_interceptport(lwkt_port_t port, lwkt_msg_t lmsg)
269 cdevallmsg_t msg = (cdevallmsg_t)lmsg;
272 switch(msg->am_lmsg.ms_cmd.cm_op) {
274 error = cnopen(&msg->am_open);
277 error = cnclose(&msg->am_close);
280 error = lwkt_forwardmsg(cn_fwd_port, &msg->am_lmsg);
287 * This is the port handler for /dev/console. These functions will basically
288 * past the request through to the actual physical device representing the
291 * Note, however, that cnopen() and cnclose() are also called from the mute
292 * code and the intercept code.
295 console_putport(lwkt_port_t port, lwkt_msg_t lmsg)
297 cdevallmsg_t msg = (cdevallmsg_t)lmsg;
300 switch(msg->am_lmsg.ms_cmd.cm_op) {
302 error = cnopen(&msg->am_open);
305 error = cnclose(&msg->am_close);
307 case CDEV_CMD_STRATEGY:
308 nostrategy(msg->am_strategy.bp);
312 error = cnioctl(&msg->am_ioctl);
315 error = nodump(msg->am_dump.msg.dev, 0, 0, 0);
318 error = nopsize(msg->am_psize.msg.dev);
321 error = cnread(&msg->am_read);
324 error = cnwrite(&msg->am_write);
327 error = cnpoll(&msg->am_poll);
329 case CDEV_CMD_KQFILTER:
330 error = cnkqfilter(&msg->am_kqfilter);
333 error = nommap(msg->am_mmap.msg.dev,
345 * cnopen() is called as a port intercept function (dev will be that of the
346 * actual physical device representing our console), and also called from
347 * the muting code and from the /dev/console switch (dev will have the
351 cnopen(struct cdevmsg_open *msg)
353 dev_t dev = msg->msg.dev;
354 int flag = msg->oflags;
355 int mode = msg->devtype;
356 dev_t cndev, physdev;
359 if (cn_tab == NULL || cn_fwd_port == NULL)
361 cndev = cn_tab->cn_dev;
362 physdev = (major(dev) == major(cndev) ? dev : cndev);
365 * If mute is active, then non console opens don't get here
366 * so we don't need to check for that. They bypass this and go
367 * straight to the device.
369 * XXX at the moment we assume that the port forwarding function
370 * is synchronous for open.
373 msg->msg.dev = physdev;
374 retval = lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg);
378 * check if we openned it via /dev/console or
379 * via the physical entry (e.g. /dev/sio0).
383 else if (physdev == cndev) {
388 dev->si_tty = physdev->si_tty;
394 * cnclose() is called as a port intercept function (dev will be that of the
395 * actual physical device representing our console), and also called from
396 * the muting code and from the /dev/console switch (dev will have the
400 cnclose(struct cdevmsg_close *msg)
402 dev_t dev = msg->msg.dev;
406 if (cn_tab == NULL || cn_fwd_port == NULL)
408 cndev = cn_tab->cn_dev;
409 cn_tp = cndev->si_tty;
411 * act appropriatly depending on whether it's /dev/console
412 * or the pysical device (e.g. /dev/sio) that's being closed.
413 * in either case, don't actually close the device unless
417 /* the physical device is about to be closed */
421 /* perform a ttyhalfclose() */
422 /* reset session and proc group */
423 ttyclearsession(cn_tp);
427 } else if (major(dev) != major(cndev)) {
428 /* the logical console is about to be closed */
436 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
442 * The following functions are dispatched solely from the /dev/console
443 * port switch. Their job is primarily to forward the request through.
444 * If the console is not attached to anything then write()'s are sunk
445 * to null and reads return 0 (mostly).
448 cnread(struct cdevmsg_read *msg)
450 if (cn_tab == NULL || cn_fwd_port == NULL)
452 msg->msg.dev = cn_tab->cn_dev;
453 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
457 cnwrite(struct cdevmsg_write *msg)
459 struct uio *uio = msg->uio;
462 if (cn_tab == NULL || cn_fwd_port == NULL) {
463 uio->uio_resid = 0; /* dump the data */
467 dev = constty->t_dev;
469 dev = cn_tab->cn_dev;
472 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
476 cnioctl(struct cdevmsg_ioctl *msg)
478 u_long cmd = msg->cmd;
481 if (cn_tab == NULL || cn_fwd_port == NULL)
483 KKASSERT(msg->td->td_proc != NULL);
485 * Superuser can always use this to wrest control of console
486 * output from the "virtual" console.
488 if (cmd == TIOCCONS && constty) {
489 error = suser(msg->td);
495 msg->msg.dev = cn_tab->cn_dev;
496 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
500 cnpoll(struct cdevmsg_poll *msg)
502 if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
504 msg->msg.dev = cn_tab->cn_dev;
505 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
509 cnkqfilter(struct cdevmsg_kqfilter *msg)
511 if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
513 msg->msg.dev = cn_tab->cn_dev;
514 return(lwkt_forwardmsg(cn_fwd_port, &msg->msg.msg));
518 * These synchronous functions are primarily used the kernel needs to
519 * access the keyboard (e.g. when running the debugger), or output data
520 * directly to the console.
526 if ((cn_tab == NULL) || cn_mute)
528 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
529 if (c == '\r') c = '\n'; /* console input is always ICRNL */
536 if ((cn_tab == NULL) || cn_mute)
538 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
546 if ((cn_tab == NULL) || cn_mute)
550 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
551 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
553 if (console_pausing && !db_active && (c == '\n')) {
555 if (console_pausing && (c == '\n')) {
557 for(cp=console_pausestr; *cp != '\0'; cp++)
558 (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
561 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
562 for(cp=console_pausestr; *cp != '\0'; cp++)
563 (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
564 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
578 if (refcount == 0 && cn_tab->cn_dbctl != NULL)
579 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
585 cn_drvinit(void *unused)
587 cdevsw_add(&cn_cdevsw, 0, 0);
588 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL,
592 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)