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 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
43 #include <sys/systm.h>
45 #include <sys/mutex.h>
48 #include <sys/fcntl.h>
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/msgbuf.h>
53 #include <sys/namei.h>
56 #include <sys/queue.h>
57 #include <sys/reboot.h>
58 #include <sys/sysctl.h>
62 #include <sys/vnode.h>
66 #include <machine/cpu.h>
67 #include <machine/clock.h>
69 static MALLOC_DEFINE(M_TTYCONS
, "tty console", "tty console handling");
71 static d_open_t cnopen
;
72 static d_close_t cnclose
;
73 static d_read_t cnread
;
74 static d_write_t cnwrite
;
75 static d_ioctl_t cnioctl
;
76 static d_poll_t cnpoll
;
77 static d_kqfilter_t cnkqfilter
;
79 static struct cdevsw cn_cdevsw
= {
80 .d_version
= D_VERSION
,
88 .d_flags
= D_TTY
| D_NEEDGIANT
,
89 .d_kqfilter
= cnkqfilter
,
93 STAILQ_ENTRY(cn_device
) cnd_next
;
95 struct consdev
*cnd_cn
;
98 #define CNDEVPATHMAX 32
99 #define CNDEVTAB_SIZE 4
100 static struct cn_device cn_devtab
[CNDEVTAB_SIZE
];
101 static STAILQ_HEAD(, cn_device
) cn_devlist
=
102 STAILQ_HEAD_INITIALIZER(cn_devlist
);
104 #define CND_INVALID(cnd, td) \
105 (cnd == NULL || cnd->cnd_vp == NULL || \
106 (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
108 static dev_t cn_udev_t
;
109 SYSCTL_OPAQUE(_machdep
, OID_AUTO
, consdev
, CTLFLAG_RD
,
110 &cn_udev_t
, sizeof cn_udev_t
, "T,struct cdev *", "");
112 int cons_avail_mask
= 0; /* Bit mask. Each registered low level console
113 * which is currently unavailable for inpit
114 * (i.e., if it is in graphics mode) will have
118 static int openflag
; /* how /dev/console was opened */
119 static int cn_is_open
;
120 static char *consbuf
; /* buffer used by `consmsgbuf' */
121 static struct callout conscallout
; /* callout for outputting to constty */
122 struct msgbuf consmsgbuf
; /* message buffer for console tty */
123 static u_char console_pausing
; /* pause after each line during probe */
124 static char *console_pausestr
=
125 "<pause; press any key to proceed to next line or '.' to end pause mode>";
126 struct tty
*constty
; /* pointer to console "window" tty */
127 static struct mtx cnputs_mtx
; /* Mutex for cnputs(). */
128 static int use_cnputs_mtx
= 0; /* != 0 if cnputs_mtx locking reqd. */
130 static void constty_timeout(void *arg
);
132 static struct consdev cons_consdev
;
133 DATA_SET(cons_set
, cons_consdev
);
134 SET_DECLARE(cons_set
, struct consdev
);
139 struct consdev
*best_cn
, *cn
, **list
;
142 * Check if we should mute the console (for security reasons perhaps)
143 * It can be changes dynamically using sysctl kern.consmute
144 * once we are up and going.
147 cn_mute
= ((boothowto
& (RB_MUTE
150 |RB_ASKNAME
)) == RB_MUTE
);
153 * Find the first console with the highest priority.
156 SET_FOREACH(list
, cons_set
) {
159 if (cn
->cn_probe
== NULL
)
162 if (cn
->cn_pri
== CN_DEAD
)
164 if (best_cn
== NULL
|| cn
->cn_pri
> best_cn
->cn_pri
)
166 if (boothowto
& RB_MULTIPLE
) {
168 * Initialize console, and attach to it.
176 if ((boothowto
& RB_MULTIPLE
) == 0) {
177 best_cn
->cn_init(best_cn
);
180 if (boothowto
& RB_PAUSE
)
183 * Make the best console the preferred console.
194 /* add a new physical console to back the virtual console */
196 cnadd(struct consdev
*cn
)
198 struct cn_device
*cnd
;
201 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
)
202 if (cnd
->cnd_cn
== cn
)
204 for (i
= 0; i
< CNDEVTAB_SIZE
; i
++) {
206 if (cnd
->cnd_cn
== NULL
)
209 if (cnd
->cnd_cn
!= NULL
)
212 if (cn
->cn_name
[0] == '\0') {
213 /* XXX: it is unclear if/where this print might output */
214 printf("WARNING: console at %p has no name\n", cn
);
216 STAILQ_INSERT_TAIL(&cn_devlist
, cnd
, cnd_next
);
218 /* Add device to the active mask. */
219 cnavailable(cn
, (cn
->cn_flags
& CN_FLAG_NOAVAIL
) == 0);
225 cnremove(struct consdev
*cn
)
227 struct cn_device
*cnd
;
230 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
) {
231 if (cnd
->cnd_cn
!= cn
)
233 STAILQ_REMOVE(&cn_devlist
, cnd
, cn_device
, cnd_next
);
234 if (cnd
->cnd_vp
!= NULL
)
235 vn_close(cnd
->cnd_vp
, openflag
, NOCRED
, NULL
);
239 /* Remove this device from available mask. */
240 for (i
= 0; i
< CNDEVTAB_SIZE
; i
++)
241 if (cnd
== &cn_devtab
[i
]) {
242 cons_avail_mask
&= ~(1 << i
);
248 * syscons gets really confused if console resources are
249 * freed after the system has initialized.
251 if (cn
->cn_term
!= NULL
)
259 cnselect(struct consdev
*cn
)
261 struct cn_device
*cnd
;
263 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
) {
264 if (cnd
->cnd_cn
!= cn
)
266 if (cnd
== STAILQ_FIRST(&cn_devlist
))
268 STAILQ_REMOVE(&cn_devlist
, cnd
, cn_device
, cnd_next
);
269 STAILQ_INSERT_HEAD(&cn_devlist
, cnd
, cnd_next
);
275 cnavailable(struct consdev
*cn
, int available
)
279 for (i
= 0; i
< CNDEVTAB_SIZE
; i
++) {
280 if (cn_devtab
[i
].cnd_cn
== cn
)
284 if (i
< CNDEVTAB_SIZE
)
285 cons_avail_mask
|= (1 << i
);
286 cn
->cn_flags
&= ~CN_FLAG_NOAVAIL
;
288 if (i
< CNDEVTAB_SIZE
)
289 cons_avail_mask
&= ~(1 << i
);
290 cn
->cn_flags
|= CN_FLAG_NOAVAIL
;
298 return (cons_avail_mask
== 0);
302 * sysctl_kern_console() provides output parseable in conscontrol(1).
305 sysctl_kern_console(SYSCTL_HANDLER_ARGS
)
307 struct cn_device
*cnd
;
308 struct consdev
*cp
, **list
;
313 sb
= sbuf_new(NULL
, NULL
, CNDEVPATHMAX
* 2, SBUF_AUTOEXTEND
);
317 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
)
318 sbuf_printf(sb
, "%s,", cnd
->cnd_cn
->cn_name
);
319 sbuf_printf(sb
, "/");
320 SET_FOREACH(list
, cons_set
) {
322 if (cp
->cn_name
[0] != '\0')
323 sbuf_printf(sb
, "%s,", cp
->cn_name
);
326 error
= sysctl_handle_string(oidp
, sbuf_data(sb
), sbuf_len(sb
), req
);
327 if (error
== 0 && req
->newptr
!= NULL
) {
335 SET_FOREACH(list
, cons_set
) {
337 if (strcmp(p
, cp
->cn_name
) != 0)
354 SYSCTL_PROC(_kern
, OID_AUTO
, console
, CTLTYPE_STRING
|CTLFLAG_RW
,
355 0, 0, sysctl_kern_console
, "A", "Console device control");
358 * User has changed the state of the console muting.
359 * This may require us to open or close the device in question.
362 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS
)
368 error
= sysctl_handle_int(oidp
, &cn_mute
, 0, req
);
369 if (error
!= 0 || req
->newptr
== NULL
)
371 if (ocn_mute
&& !cn_mute
&& cn_is_open
)
372 error
= cnopen(NULL
, openflag
, 0, curthread
);
373 else if (!ocn_mute
&& cn_mute
&& cn_is_open
) {
374 error
= cnclose(NULL
, openflag
, 0, curthread
);
375 cn_is_open
= 1; /* XXX hack */
380 SYSCTL_PROC(_kern
, OID_AUTO
, consmute
, CTLTYPE_INT
|CTLFLAG_RW
,
381 0, sizeof(cn_mute
), sysctl_kern_consmute
, "I", "");
384 cn_devopen(struct cn_device
*cnd
, struct thread
*td
, int forceopen
)
386 char path
[CNDEVPATHMAX
];
393 if ((vp
= cnd
->cnd_vp
) != NULL
) {
394 if (!forceopen
&& vp
->v_type
!= VBAD
) {
396 csw
= dev_refthread(dev
);
399 error
= (*csw
->d_open
)(dev
, openflag
, 0, td
);
404 vn_close(vp
, openflag
, td
->td_ucred
, td
);
406 snprintf(path
, sizeof(path
), "/dev/%s", cnd
->cnd_cn
->cn_name
);
407 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, path
, td
);
408 error
= vn_open(&nd
, &openflag
, 0, NULL
);
410 NDFREE(&nd
, NDF_ONLY_PNBUF
);
411 VOP_UNLOCK(nd
.ni_vp
, 0);
412 if (nd
.ni_vp
->v_type
== VCHR
)
413 cnd
->cnd_vp
= nd
.ni_vp
;
415 vn_close(nd
.ni_vp
, openflag
, td
->td_ucred
, td
);
417 return (cnd
->cnd_vp
!= NULL
);
421 cnopen(struct cdev
*dev
, int flag
, int mode
, struct thread
*td
)
423 struct cn_device
*cnd
;
425 openflag
= flag
| FWRITE
; /* XXX */
426 cn_is_open
= 1; /* console is logically open */
429 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
)
430 cn_devopen(cnd
, td
, 0);
435 cnclose(struct cdev
*dev
, int flag
, int mode
, struct thread
*td
)
437 struct cn_device
*cnd
;
440 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
) {
441 if ((vp
= cnd
->cnd_vp
) == NULL
)
444 vn_close(vp
, openflag
, td
->td_ucred
, td
);
451 cnread(struct cdev
*dev
, struct uio
*uio
, int flag
)
453 struct cn_device
*cnd
;
457 cnd
= STAILQ_FIRST(&cn_devlist
);
458 if (cn_mute
|| CND_INVALID(cnd
, curthread
))
460 dev
= cnd
->cnd_vp
->v_rdev
;
461 csw
= dev_refthread(dev
);
464 error
= (csw
->d_read
)(dev
, uio
, flag
);
470 cnwrite(struct cdev
*dev
, struct uio
*uio
, int flag
)
472 struct cn_device
*cnd
;
476 cnd
= STAILQ_FIRST(&cn_devlist
);
477 if (cn_mute
|| CND_INVALID(cnd
, curthread
))
480 dev
= constty
->t_dev
;
482 dev
= cnd
->cnd_vp
->v_rdev
;
485 csw
= dev_refthread(dev
);
488 error
= (csw
->d_write
)(dev
, uio
, flag
);
493 uio
->uio_resid
= 0; /* dump the data */
498 cnioctl(struct cdev
*dev
, u_long cmd
, caddr_t data
, int flag
, struct thread
*td
)
500 struct cn_device
*cnd
;
504 cnd
= STAILQ_FIRST(&cn_devlist
);
505 if (cn_mute
|| CND_INVALID(cnd
, td
))
508 * Superuser can always use this to wrest control of console
509 * output from the "virtual" console.
511 if (cmd
== TIOCCONS
&& constty
) {
512 error
= priv_check(td
, PRIV_TTY_CONSOLE
);
518 dev
= cnd
->cnd_vp
->v_rdev
;
520 return (0); /* XXX : ENOTTY ? */
521 csw
= dev_refthread(dev
);
524 error
= (csw
->d_ioctl
)(dev
, cmd
, data
, flag
, td
);
531 * poll/kqfilter do not appear to be correct
534 cnpoll(struct cdev
*dev
, int events
, struct thread
*td
)
536 struct cn_device
*cnd
;
540 cnd
= STAILQ_FIRST(&cn_devlist
);
541 if (cn_mute
|| CND_INVALID(cnd
, td
))
543 dev
= cnd
->cnd_vp
->v_rdev
;
546 csw
= dev_refthread(dev
);
549 error
= (csw
->d_poll
)(dev
, events
, td
);
555 cnkqfilter(struct cdev
*dev
, struct knote
*kn
)
557 struct cn_device
*cnd
;
561 cnd
= STAILQ_FIRST(&cn_devlist
);
562 if (cn_mute
|| CND_INVALID(cnd
, curthread
))
564 dev
= cnd
->cnd_vp
->v_rdev
;
567 csw
= dev_refthread(dev
);
570 error
= (csw
->d_kqfilter
)(dev
, kn
);
576 * Low level console routines.
585 while ((c
= cncheckc()) == -1)
588 c
= '\n'; /* console input is always ICRNL */
595 struct cn_device
*cnd
;
601 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
) {
603 if (!kdb_active
|| !(cn
->cn_flags
& CN_FLAG_NODEBUG
)) {
604 if (cn
->cn_checkc
!= NULL
)
605 c
= cn
->cn_checkc(cn
);
619 struct cn_device
*cnd
;
623 if (cn_mute
|| c
== '\0')
625 STAILQ_FOREACH(cnd
, &cn_devlist
, cnd_next
) {
627 if (!kdb_active
|| !(cn
->cn_flags
& CN_FLAG_NODEBUG
)) {
629 cn
->cn_putc(cn
, '\r');
633 if (console_pausing
&& c
== '\n' && !kdb_active
) {
634 for (cp
= console_pausestr
; *cp
!= '\0'; cp
++)
639 for (cp
= console_pausestr
; *cp
!= '\0'; cp
++)
651 if (use_cnputs_mtx
) {
652 mtx_lock_spin(&cnputs_mtx
);
656 while ((c
= *p
++) != '\0')
660 mtx_unlock_spin(&cnputs_mtx
);
663 static int consmsgbuf_size
= 8192;
664 SYSCTL_INT(_kern
, OID_AUTO
, consmsgbuf_size
, CTLFLAG_RW
, &consmsgbuf_size
, 0,
668 * Redirect console output to a tty.
671 constty_set(struct tty
*tp
)
675 KASSERT(tp
!= NULL
, ("constty_set: NULL tp"));
676 if (consbuf
== NULL
) {
677 size
= consmsgbuf_size
;
678 consbuf
= malloc(size
, M_TTYCONS
, M_WAITOK
);
679 msgbuf_init(&consmsgbuf
, consbuf
, size
);
680 callout_init(&conscallout
, 0);
683 constty_timeout(NULL
);
687 * Disable console redirection to a tty.
697 callout_stop(&conscallout
);
698 while ((c
= msgbuf_getchar(&consmsgbuf
)) != -1)
700 free(consbuf
, M_TTYCONS
);
704 /* Times per second to check for pending console tty messages. */
705 static int constty_wakeups_per_second
= 5;
706 SYSCTL_INT(_kern
, OID_AUTO
, constty_wakeups_per_second
, CTLFLAG_RW
,
707 &constty_wakeups_per_second
, 0, "");
710 constty_timeout(void *arg
)
714 if (constty
!= NULL
) {
716 while ((c
= msgbuf_getchar(&consmsgbuf
)) != -1) {
717 if (tty_putchar(constty
, c
) < 0) {
727 if (constty
!= NULL
) {
728 callout_reset(&conscallout
, hz
/ constty_wakeups_per_second
,
729 constty_timeout
, NULL
);
731 /* Deallocate the constty buffer memory. */
737 cn_drvinit(void *unused
)
740 make_dev(&cn_cdevsw
, 0, UID_ROOT
, GID_WHEEL
, 0600, "console");
742 mtx_init(&cnputs_mtx
, "cnputs_mtx", NULL
, MTX_SPIN
| MTX_NOWITNESS
);
746 SYSINIT(cndev
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
, cn_drvinit
, NULL
);
749 * Sysbeep(), if we have hardware for it
752 #ifdef HAS_TIMER_SPKR
757 sysbeepstop(void *chan
)
760 timer_spkr_release();
765 sysbeep(int pitch
, int period
)
768 if (timer_spkr_acquire()) {
770 /* Something else owns it. */
774 timer_spkr_setfreq(pitch
);
777 timeout(sysbeepstop
, (void *)NULL
, period
);
785 * No hardware, no sound
789 sysbeep(int pitch __unused
, int period __unused
)