1c9dba40cSEd Schouten /*- 2c9dba40cSEd Schouten * Copyright (c) 1988 University of Utah. 3c9dba40cSEd Schouten * Copyright (c) 1991 The Regents of the University of California. 4c9dba40cSEd Schouten * All rights reserved. 5c9dba40cSEd Schouten * 6c9dba40cSEd Schouten * This code is derived from software contributed to Berkeley by 7c9dba40cSEd Schouten * the Systems Programming Group of the University of Utah Computer 8c9dba40cSEd Schouten * Science Department. 9c9dba40cSEd Schouten * 10c9dba40cSEd Schouten * Redistribution and use in source and binary forms, with or without 11c9dba40cSEd Schouten * modification, are permitted provided that the following conditions 12c9dba40cSEd Schouten * are met: 13c9dba40cSEd Schouten * 1. Redistributions of source code must retain the above copyright 14c9dba40cSEd Schouten * notice, this list of conditions and the following disclaimer. 15c9dba40cSEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 16c9dba40cSEd Schouten * notice, this list of conditions and the following disclaimer in the 17c9dba40cSEd Schouten * documentation and/or other materials provided with the distribution. 18c9dba40cSEd Schouten * 4. Neither the name of the University nor the names of its contributors 19c9dba40cSEd Schouten * may be used to endorse or promote products derived from this software 20c9dba40cSEd Schouten * without specific prior written permission. 21c9dba40cSEd Schouten * 22c9dba40cSEd Schouten * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23c9dba40cSEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24c9dba40cSEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25c9dba40cSEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26c9dba40cSEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27c9dba40cSEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28c9dba40cSEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29c9dba40cSEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30c9dba40cSEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31c9dba40cSEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32c9dba40cSEd Schouten * SUCH DAMAGE. 33c9dba40cSEd Schouten * 34c9dba40cSEd Schouten * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 35c9dba40cSEd Schouten */ 36c9dba40cSEd Schouten 37c9dba40cSEd Schouten #include <sys/cdefs.h> 38c9dba40cSEd Schouten __FBSDID("$FreeBSD$"); 39c9dba40cSEd Schouten 40c9dba40cSEd Schouten #include "opt_ddb.h" 41c9dba40cSEd Schouten 42c9dba40cSEd Schouten #include <sys/param.h> 43c9dba40cSEd Schouten #include <sys/systm.h> 44c9dba40cSEd Schouten #include <sys/lock.h> 45c9dba40cSEd Schouten #include <sys/mutex.h> 46c9dba40cSEd Schouten #include <sys/conf.h> 47c9dba40cSEd Schouten #include <sys/cons.h> 48c9dba40cSEd Schouten #include <sys/fcntl.h> 49c9dba40cSEd Schouten #include <sys/kdb.h> 50c9dba40cSEd Schouten #include <sys/kernel.h> 51c9dba40cSEd Schouten #include <sys/malloc.h> 52c9dba40cSEd Schouten #include <sys/msgbuf.h> 53c9dba40cSEd Schouten #include <sys/namei.h> 54c9dba40cSEd Schouten #include <sys/priv.h> 55c9dba40cSEd Schouten #include <sys/proc.h> 56c9dba40cSEd Schouten #include <sys/queue.h> 57c9dba40cSEd Schouten #include <sys/reboot.h> 58c9dba40cSEd Schouten #include <sys/sysctl.h> 59c9dba40cSEd Schouten #include <sys/sbuf.h> 60c9dba40cSEd Schouten #include <sys/tty.h> 61c9dba40cSEd Schouten #include <sys/uio.h> 62c9dba40cSEd Schouten #include <sys/vnode.h> 63c9dba40cSEd Schouten 64c9dba40cSEd Schouten #include <ddb/ddb.h> 65c9dba40cSEd Schouten 66c9dba40cSEd Schouten #include <machine/cpu.h> 67c9dba40cSEd Schouten #include <machine/clock.h> 68c9dba40cSEd Schouten 69c9dba40cSEd Schouten static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling"); 70c9dba40cSEd Schouten 71c9dba40cSEd Schouten struct cn_device { 72c9dba40cSEd Schouten STAILQ_ENTRY(cn_device) cnd_next; 73c9dba40cSEd Schouten struct consdev *cnd_cn; 74c9dba40cSEd Schouten }; 75c9dba40cSEd Schouten 76c9dba40cSEd Schouten #define CNDEVPATHMAX 32 77c9dba40cSEd Schouten #define CNDEVTAB_SIZE 4 78c9dba40cSEd Schouten static struct cn_device cn_devtab[CNDEVTAB_SIZE]; 79c9dba40cSEd Schouten static STAILQ_HEAD(, cn_device) cn_devlist = 80c9dba40cSEd Schouten STAILQ_HEAD_INITIALIZER(cn_devlist); 81c9dba40cSEd Schouten 82c9dba40cSEd Schouten int cons_avail_mask = 0; /* Bit mask. Each registered low level console 83c9dba40cSEd Schouten * which is currently unavailable for inpit 84c9dba40cSEd Schouten * (i.e., if it is in graphics mode) will have 85c9dba40cSEd Schouten * this bit cleared. 86c9dba40cSEd Schouten */ 87c9dba40cSEd Schouten static int cn_mute; 88c9dba40cSEd Schouten static char *consbuf; /* buffer used by `consmsgbuf' */ 89c9dba40cSEd Schouten static struct callout conscallout; /* callout for outputting to constty */ 90c9dba40cSEd Schouten struct msgbuf consmsgbuf; /* message buffer for console tty */ 91c9dba40cSEd Schouten static u_char console_pausing; /* pause after each line during probe */ 92c9dba40cSEd Schouten static char *console_pausestr= 93c9dba40cSEd Schouten "<pause; press any key to proceed to next line or '.' to end pause mode>"; 94c9dba40cSEd Schouten struct tty *constty; /* pointer to console "window" tty */ 95c9dba40cSEd Schouten static struct mtx cnputs_mtx; /* Mutex for cnputs(). */ 96c9dba40cSEd Schouten static int use_cnputs_mtx = 0; /* != 0 if cnputs_mtx locking reqd. */ 97c9dba40cSEd Schouten 98c9dba40cSEd Schouten static void constty_timeout(void *arg); 99c9dba40cSEd Schouten 100c9dba40cSEd Schouten static struct consdev cons_consdev; 101c9dba40cSEd Schouten DATA_SET(cons_set, cons_consdev); 102c9dba40cSEd Schouten SET_DECLARE(cons_set, struct consdev); 103c9dba40cSEd Schouten 104c9dba40cSEd Schouten void 105c9dba40cSEd Schouten cninit(void) 106c9dba40cSEd Schouten { 107c9dba40cSEd Schouten struct consdev *best_cn, *cn, **list; 108c9dba40cSEd Schouten 109c9dba40cSEd Schouten /* 110c9dba40cSEd Schouten * Check if we should mute the console (for security reasons perhaps) 111c9dba40cSEd Schouten * It can be changes dynamically using sysctl kern.consmute 112c9dba40cSEd Schouten * once we are up and going. 113c9dba40cSEd Schouten * 114c9dba40cSEd Schouten */ 115c9dba40cSEd Schouten cn_mute = ((boothowto & (RB_MUTE 116c9dba40cSEd Schouten |RB_SINGLE 117c9dba40cSEd Schouten |RB_VERBOSE 118c9dba40cSEd Schouten |RB_ASKNAME)) == RB_MUTE); 119c9dba40cSEd Schouten 120c9dba40cSEd Schouten /* 121c9dba40cSEd Schouten * Find the first console with the highest priority. 122c9dba40cSEd Schouten */ 123c9dba40cSEd Schouten best_cn = NULL; 124c9dba40cSEd Schouten SET_FOREACH(list, cons_set) { 125c9dba40cSEd Schouten cn = *list; 126c9dba40cSEd Schouten cnremove(cn); 1272992abe0SEd Schouten /* Skip cons_consdev. */ 1282992abe0SEd Schouten if (cn->cn_ops == NULL) 129c9dba40cSEd Schouten continue; 1302992abe0SEd Schouten cn->cn_ops->cn_probe(cn); 131c9dba40cSEd Schouten if (cn->cn_pri == CN_DEAD) 132c9dba40cSEd Schouten continue; 133c9dba40cSEd Schouten if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri) 134c9dba40cSEd Schouten best_cn = cn; 135c9dba40cSEd Schouten if (boothowto & RB_MULTIPLE) { 136c9dba40cSEd Schouten /* 137c9dba40cSEd Schouten * Initialize console, and attach to it. 138c9dba40cSEd Schouten */ 1392992abe0SEd Schouten cn->cn_ops->cn_init(cn); 140c9dba40cSEd Schouten cnadd(cn); 141c9dba40cSEd Schouten } 142c9dba40cSEd Schouten } 143c9dba40cSEd Schouten if (best_cn == NULL) 144c9dba40cSEd Schouten return; 145c9dba40cSEd Schouten if ((boothowto & RB_MULTIPLE) == 0) { 1462992abe0SEd Schouten best_cn->cn_ops->cn_init(best_cn); 147c9dba40cSEd Schouten cnadd(best_cn); 148c9dba40cSEd Schouten } 149c9dba40cSEd Schouten if (boothowto & RB_PAUSE) 150c9dba40cSEd Schouten console_pausing = 1; 151c9dba40cSEd Schouten /* 152c9dba40cSEd Schouten * Make the best console the preferred console. 153c9dba40cSEd Schouten */ 154c9dba40cSEd Schouten cnselect(best_cn); 155c9dba40cSEd Schouten } 156c9dba40cSEd Schouten 157c9dba40cSEd Schouten void 158c9dba40cSEd Schouten cninit_finish() 159c9dba40cSEd Schouten { 160c9dba40cSEd Schouten console_pausing = 0; 161c9dba40cSEd Schouten } 162c9dba40cSEd Schouten 163c9dba40cSEd Schouten /* add a new physical console to back the virtual console */ 164c9dba40cSEd Schouten int 165c9dba40cSEd Schouten cnadd(struct consdev *cn) 166c9dba40cSEd Schouten { 167c9dba40cSEd Schouten struct cn_device *cnd; 168c9dba40cSEd Schouten int i; 169c9dba40cSEd Schouten 170c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 171c9dba40cSEd Schouten if (cnd->cnd_cn == cn) 172c9dba40cSEd Schouten return (0); 173c9dba40cSEd Schouten for (i = 0; i < CNDEVTAB_SIZE; i++) { 174c9dba40cSEd Schouten cnd = &cn_devtab[i]; 175c9dba40cSEd Schouten if (cnd->cnd_cn == NULL) 176c9dba40cSEd Schouten break; 177c9dba40cSEd Schouten } 178c9dba40cSEd Schouten if (cnd->cnd_cn != NULL) 179c9dba40cSEd Schouten return (ENOMEM); 180c9dba40cSEd Schouten cnd->cnd_cn = cn; 181c9dba40cSEd Schouten if (cn->cn_name[0] == '\0') { 182c9dba40cSEd Schouten /* XXX: it is unclear if/where this print might output */ 183c9dba40cSEd Schouten printf("WARNING: console at %p has no name\n", cn); 184c9dba40cSEd Schouten } 185c9dba40cSEd Schouten STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next); 186c9dba40cSEd Schouten if (STAILQ_FIRST(&cn_devlist) == cnd) 187c9dba40cSEd Schouten ttyconsdev_select(cnd->cnd_cn->cn_name); 188c9dba40cSEd Schouten 189c9dba40cSEd Schouten /* Add device to the active mask. */ 190c9dba40cSEd Schouten cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0); 191c9dba40cSEd Schouten 192c9dba40cSEd Schouten return (0); 193c9dba40cSEd Schouten } 194c9dba40cSEd Schouten 195c9dba40cSEd Schouten void 196c9dba40cSEd Schouten cnremove(struct consdev *cn) 197c9dba40cSEd Schouten { 198c9dba40cSEd Schouten struct cn_device *cnd; 199c9dba40cSEd Schouten int i; 200c9dba40cSEd Schouten 201c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 202c9dba40cSEd Schouten if (cnd->cnd_cn != cn) 203c9dba40cSEd Schouten continue; 204c9dba40cSEd Schouten if (STAILQ_FIRST(&cn_devlist) == cnd) 205c9dba40cSEd Schouten ttyconsdev_select(NULL); 206c9dba40cSEd Schouten STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 207c9dba40cSEd Schouten cnd->cnd_cn = NULL; 208c9dba40cSEd Schouten 209c9dba40cSEd Schouten /* Remove this device from available mask. */ 210c9dba40cSEd Schouten for (i = 0; i < CNDEVTAB_SIZE; i++) 211c9dba40cSEd Schouten if (cnd == &cn_devtab[i]) { 212c9dba40cSEd Schouten cons_avail_mask &= ~(1 << i); 213c9dba40cSEd Schouten break; 214c9dba40cSEd Schouten } 215c9dba40cSEd Schouten #if 0 216c9dba40cSEd Schouten /* 217c9dba40cSEd Schouten * XXX 218c9dba40cSEd Schouten * syscons gets really confused if console resources are 219c9dba40cSEd Schouten * freed after the system has initialized. 220c9dba40cSEd Schouten */ 221c9dba40cSEd Schouten if (cn->cn_term != NULL) 2222992abe0SEd Schouten cn->cn_ops->cn_term(cn); 223c9dba40cSEd Schouten #endif 224c9dba40cSEd Schouten return; 225c9dba40cSEd Schouten } 226c9dba40cSEd Schouten } 227c9dba40cSEd Schouten 228c9dba40cSEd Schouten void 229c9dba40cSEd Schouten cnselect(struct consdev *cn) 230c9dba40cSEd Schouten { 231c9dba40cSEd Schouten struct cn_device *cnd; 232c9dba40cSEd Schouten 233c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 234c9dba40cSEd Schouten if (cnd->cnd_cn != cn) 235c9dba40cSEd Schouten continue; 236c9dba40cSEd Schouten if (cnd == STAILQ_FIRST(&cn_devlist)) 237c9dba40cSEd Schouten return; 238c9dba40cSEd Schouten STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next); 239c9dba40cSEd Schouten STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next); 240c9dba40cSEd Schouten ttyconsdev_select(cnd->cnd_cn->cn_name); 241c9dba40cSEd Schouten return; 242c9dba40cSEd Schouten } 243c9dba40cSEd Schouten } 244c9dba40cSEd Schouten 245c9dba40cSEd Schouten void 246c9dba40cSEd Schouten cnavailable(struct consdev *cn, int available) 247c9dba40cSEd Schouten { 248c9dba40cSEd Schouten int i; 249c9dba40cSEd Schouten 250c9dba40cSEd Schouten for (i = 0; i < CNDEVTAB_SIZE; i++) { 251c9dba40cSEd Schouten if (cn_devtab[i].cnd_cn == cn) 252c9dba40cSEd Schouten break; 253c9dba40cSEd Schouten } 254c9dba40cSEd Schouten if (available) { 255c9dba40cSEd Schouten if (i < CNDEVTAB_SIZE) 256c9dba40cSEd Schouten cons_avail_mask |= (1 << i); 257c9dba40cSEd Schouten cn->cn_flags &= ~CN_FLAG_NOAVAIL; 258c9dba40cSEd Schouten } else { 259c9dba40cSEd Schouten if (i < CNDEVTAB_SIZE) 260c9dba40cSEd Schouten cons_avail_mask &= ~(1 << i); 261c9dba40cSEd Schouten cn->cn_flags |= CN_FLAG_NOAVAIL; 262c9dba40cSEd Schouten } 263c9dba40cSEd Schouten } 264c9dba40cSEd Schouten 265c9dba40cSEd Schouten int 266c9dba40cSEd Schouten cnunavailable(void) 267c9dba40cSEd Schouten { 268c9dba40cSEd Schouten 269c9dba40cSEd Schouten return (cons_avail_mask == 0); 270c9dba40cSEd Schouten } 271c9dba40cSEd Schouten 272c9dba40cSEd Schouten /* 273c9dba40cSEd Schouten * sysctl_kern_console() provides output parseable in conscontrol(1). 274c9dba40cSEd Schouten */ 275c9dba40cSEd Schouten static int 276c9dba40cSEd Schouten sysctl_kern_console(SYSCTL_HANDLER_ARGS) 277c9dba40cSEd Schouten { 278c9dba40cSEd Schouten struct cn_device *cnd; 279c9dba40cSEd Schouten struct consdev *cp, **list; 280c9dba40cSEd Schouten char *p; 281c9dba40cSEd Schouten int delete, error; 282c9dba40cSEd Schouten struct sbuf *sb; 283c9dba40cSEd Schouten 284c9dba40cSEd Schouten sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND); 285c9dba40cSEd Schouten if (sb == NULL) 286c9dba40cSEd Schouten return (ENOMEM); 287c9dba40cSEd Schouten sbuf_clear(sb); 288c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) 289c9dba40cSEd Schouten sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name); 290c9dba40cSEd Schouten sbuf_printf(sb, "/"); 291c9dba40cSEd Schouten SET_FOREACH(list, cons_set) { 292c9dba40cSEd Schouten cp = *list; 293c9dba40cSEd Schouten if (cp->cn_name[0] != '\0') 294c9dba40cSEd Schouten sbuf_printf(sb, "%s,", cp->cn_name); 295c9dba40cSEd Schouten } 296c9dba40cSEd Schouten sbuf_finish(sb); 297c9dba40cSEd Schouten error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); 298c9dba40cSEd Schouten if (error == 0 && req->newptr != NULL) { 299c9dba40cSEd Schouten p = sbuf_data(sb); 300c9dba40cSEd Schouten error = ENXIO; 301c9dba40cSEd Schouten delete = 0; 302c9dba40cSEd Schouten if (*p == '-') { 303c9dba40cSEd Schouten delete = 1; 304c9dba40cSEd Schouten p++; 305c9dba40cSEd Schouten } 306c9dba40cSEd Schouten SET_FOREACH(list, cons_set) { 307c9dba40cSEd Schouten cp = *list; 308c9dba40cSEd Schouten if (strcmp(p, cp->cn_name) != 0) 309c9dba40cSEd Schouten continue; 310c9dba40cSEd Schouten if (delete) { 311c9dba40cSEd Schouten cnremove(cp); 312c9dba40cSEd Schouten error = 0; 313c9dba40cSEd Schouten } else { 314c9dba40cSEd Schouten error = cnadd(cp); 315c9dba40cSEd Schouten if (error == 0) 316c9dba40cSEd Schouten cnselect(cp); 317c9dba40cSEd Schouten } 318c9dba40cSEd Schouten break; 319c9dba40cSEd Schouten } 320c9dba40cSEd Schouten } 321c9dba40cSEd Schouten sbuf_delete(sb); 322c9dba40cSEd Schouten return (error); 323c9dba40cSEd Schouten } 324c9dba40cSEd Schouten 325c9dba40cSEd Schouten SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW, 326c9dba40cSEd Schouten 0, 0, sysctl_kern_console, "A", "Console device control"); 327c9dba40cSEd Schouten 328c9dba40cSEd Schouten /* 329c9dba40cSEd Schouten * User has changed the state of the console muting. 330c9dba40cSEd Schouten * This may require us to open or close the device in question. 331c9dba40cSEd Schouten */ 332c9dba40cSEd Schouten static int 333c9dba40cSEd Schouten sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) 334c9dba40cSEd Schouten { 335c9dba40cSEd Schouten int error; 336c9dba40cSEd Schouten 337c9dba40cSEd Schouten error = sysctl_handle_int(oidp, &cn_mute, 0, req); 338c9dba40cSEd Schouten if (error != 0 || req->newptr == NULL) 339c9dba40cSEd Schouten return (error); 340c9dba40cSEd Schouten return (error); 341c9dba40cSEd Schouten } 342c9dba40cSEd Schouten 343c9dba40cSEd Schouten SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, 344a0c87b74SGavin Atkinson 0, sizeof(cn_mute), sysctl_kern_consmute, "I", 345a0c87b74SGavin Atkinson "State of the console muting"); 346c9dba40cSEd Schouten 347*9976156fSAndriy Gapon void 348*9976156fSAndriy Gapon cngrab() 349*9976156fSAndriy Gapon { 350*9976156fSAndriy Gapon struct cn_device *cnd; 351*9976156fSAndriy Gapon struct consdev *cn; 352*9976156fSAndriy Gapon 353*9976156fSAndriy Gapon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 354*9976156fSAndriy Gapon cn = cnd->cnd_cn; 355*9976156fSAndriy Gapon if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 356*9976156fSAndriy Gapon cn->cn_ops->cn_grab(cn); 357*9976156fSAndriy Gapon } 358*9976156fSAndriy Gapon } 359*9976156fSAndriy Gapon 360*9976156fSAndriy Gapon void 361*9976156fSAndriy Gapon cnungrab() 362*9976156fSAndriy Gapon { 363*9976156fSAndriy Gapon struct cn_device *cnd; 364*9976156fSAndriy Gapon struct consdev *cn; 365*9976156fSAndriy Gapon 366*9976156fSAndriy Gapon STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 367*9976156fSAndriy Gapon cn = cnd->cnd_cn; 368*9976156fSAndriy Gapon if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) 369*9976156fSAndriy Gapon cn->cn_ops->cn_ungrab(cn); 370*9976156fSAndriy Gapon } 371*9976156fSAndriy Gapon } 372*9976156fSAndriy Gapon 373c9dba40cSEd Schouten /* 374c9dba40cSEd Schouten * Low level console routines. 375c9dba40cSEd Schouten */ 376c9dba40cSEd Schouten int 377c9dba40cSEd Schouten cngetc(void) 378c9dba40cSEd Schouten { 379c9dba40cSEd Schouten int c; 380c9dba40cSEd Schouten 381c9dba40cSEd Schouten if (cn_mute) 382c9dba40cSEd Schouten return (-1); 383c9dba40cSEd Schouten while ((c = cncheckc()) == -1) 384c9dba40cSEd Schouten ; 385c9dba40cSEd Schouten if (c == '\r') 386c9dba40cSEd Schouten c = '\n'; /* console input is always ICRNL */ 387c9dba40cSEd Schouten return (c); 388c9dba40cSEd Schouten } 389c9dba40cSEd Schouten 390c9dba40cSEd Schouten int 391c9dba40cSEd Schouten cncheckc(void) 392c9dba40cSEd Schouten { 393c9dba40cSEd Schouten struct cn_device *cnd; 394c9dba40cSEd Schouten struct consdev *cn; 395c9dba40cSEd Schouten int c; 396c9dba40cSEd Schouten 397c9dba40cSEd Schouten if (cn_mute) 398c9dba40cSEd Schouten return (-1); 399c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 400c9dba40cSEd Schouten cn = cnd->cnd_cn; 401c9dba40cSEd Schouten if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 4022992abe0SEd Schouten c = cn->cn_ops->cn_getc(cn); 4032992abe0SEd Schouten if (c != -1) 404c9dba40cSEd Schouten return (c); 405c9dba40cSEd Schouten } 406c9dba40cSEd Schouten } 407c9dba40cSEd Schouten return (-1); 408c9dba40cSEd Schouten } 409c9dba40cSEd Schouten 410c9dba40cSEd Schouten void 411c9dba40cSEd Schouten cnputc(int c) 412c9dba40cSEd Schouten { 413c9dba40cSEd Schouten struct cn_device *cnd; 414c9dba40cSEd Schouten struct consdev *cn; 415c9dba40cSEd Schouten char *cp; 416c9dba40cSEd Schouten 417c9dba40cSEd Schouten if (cn_mute || c == '\0') 418c9dba40cSEd Schouten return; 419c9dba40cSEd Schouten STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) { 420c9dba40cSEd Schouten cn = cnd->cnd_cn; 421c9dba40cSEd Schouten if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) { 422c9dba40cSEd Schouten if (c == '\n') 4232992abe0SEd Schouten cn->cn_ops->cn_putc(cn, '\r'); 4242992abe0SEd Schouten cn->cn_ops->cn_putc(cn, c); 425c9dba40cSEd Schouten } 426c9dba40cSEd Schouten } 427c9dba40cSEd Schouten if (console_pausing && c == '\n' && !kdb_active) { 428c9dba40cSEd Schouten for (cp = console_pausestr; *cp != '\0'; cp++) 429c9dba40cSEd Schouten cnputc(*cp); 430c9dba40cSEd Schouten if (cngetc() == '.') 431c9dba40cSEd Schouten console_pausing = 0; 432c9dba40cSEd Schouten cnputc('\r'); 433c9dba40cSEd Schouten for (cp = console_pausestr; *cp != '\0'; cp++) 434c9dba40cSEd Schouten cnputc(' '); 435c9dba40cSEd Schouten cnputc('\r'); 436c9dba40cSEd Schouten } 437c9dba40cSEd Schouten } 438c9dba40cSEd Schouten 439c9dba40cSEd Schouten void 440c9dba40cSEd Schouten cnputs(char *p) 441c9dba40cSEd Schouten { 442c9dba40cSEd Schouten int c; 443c9dba40cSEd Schouten int unlock_reqd = 0; 444c9dba40cSEd Schouten 445c9dba40cSEd Schouten if (use_cnputs_mtx) { 446c9dba40cSEd Schouten mtx_lock_spin(&cnputs_mtx); 447c9dba40cSEd Schouten unlock_reqd = 1; 448c9dba40cSEd Schouten } 449c9dba40cSEd Schouten 450c9dba40cSEd Schouten while ((c = *p++) != '\0') 451c9dba40cSEd Schouten cnputc(c); 452c9dba40cSEd Schouten 453c9dba40cSEd Schouten if (unlock_reqd) 454c9dba40cSEd Schouten mtx_unlock_spin(&cnputs_mtx); 455c9dba40cSEd Schouten } 456c9dba40cSEd Schouten 457c9dba40cSEd Schouten static int consmsgbuf_size = 8192; 458c9dba40cSEd Schouten SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0, 459a0c87b74SGavin Atkinson "Console tty buffer size"); 460c9dba40cSEd Schouten 461c9dba40cSEd Schouten /* 462c9dba40cSEd Schouten * Redirect console output to a tty. 463c9dba40cSEd Schouten */ 464c9dba40cSEd Schouten void 465c9dba40cSEd Schouten constty_set(struct tty *tp) 466c9dba40cSEd Schouten { 467c9dba40cSEd Schouten int size; 468c9dba40cSEd Schouten 469c9dba40cSEd Schouten KASSERT(tp != NULL, ("constty_set: NULL tp")); 470c9dba40cSEd Schouten if (consbuf == NULL) { 471c9dba40cSEd Schouten size = consmsgbuf_size; 472c9dba40cSEd Schouten consbuf = malloc(size, M_TTYCONS, M_WAITOK); 473c9dba40cSEd Schouten msgbuf_init(&consmsgbuf, consbuf, size); 474c9dba40cSEd Schouten callout_init(&conscallout, 0); 475c9dba40cSEd Schouten } 476c9dba40cSEd Schouten constty = tp; 477c9dba40cSEd Schouten constty_timeout(NULL); 478c9dba40cSEd Schouten } 479c9dba40cSEd Schouten 480c9dba40cSEd Schouten /* 481c9dba40cSEd Schouten * Disable console redirection to a tty. 482c9dba40cSEd Schouten */ 483c9dba40cSEd Schouten void 484c9dba40cSEd Schouten constty_clear(void) 485c9dba40cSEd Schouten { 486c9dba40cSEd Schouten int c; 487c9dba40cSEd Schouten 488c9dba40cSEd Schouten constty = NULL; 489c9dba40cSEd Schouten if (consbuf == NULL) 490c9dba40cSEd Schouten return; 491c9dba40cSEd Schouten callout_stop(&conscallout); 492c9dba40cSEd Schouten while ((c = msgbuf_getchar(&consmsgbuf)) != -1) 493c9dba40cSEd Schouten cnputc(c); 494c9dba40cSEd Schouten free(consbuf, M_TTYCONS); 495c9dba40cSEd Schouten consbuf = NULL; 496c9dba40cSEd Schouten } 497c9dba40cSEd Schouten 498c9dba40cSEd Schouten /* Times per second to check for pending console tty messages. */ 499c9dba40cSEd Schouten static int constty_wakeups_per_second = 5; 500c9dba40cSEd Schouten SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW, 501a0c87b74SGavin Atkinson &constty_wakeups_per_second, 0, 502a0c87b74SGavin Atkinson "Times per second to check for pending console tty messages"); 503c9dba40cSEd Schouten 504c9dba40cSEd Schouten static void 505c9dba40cSEd Schouten constty_timeout(void *arg) 506c9dba40cSEd Schouten { 507c9dba40cSEd Schouten int c; 508c9dba40cSEd Schouten 509c9dba40cSEd Schouten if (constty != NULL) { 510c9dba40cSEd Schouten tty_lock(constty); 511c9dba40cSEd Schouten while ((c = msgbuf_getchar(&consmsgbuf)) != -1) { 512c9dba40cSEd Schouten if (tty_putchar(constty, c) < 0) { 513c9dba40cSEd Schouten tty_unlock(constty); 514c9dba40cSEd Schouten constty = NULL; 515c9dba40cSEd Schouten break; 516c9dba40cSEd Schouten } 517c9dba40cSEd Schouten } 518c9dba40cSEd Schouten 519c9dba40cSEd Schouten if (constty != NULL) 520c9dba40cSEd Schouten tty_unlock(constty); 521c9dba40cSEd Schouten } 522c9dba40cSEd Schouten if (constty != NULL) { 523c9dba40cSEd Schouten callout_reset(&conscallout, hz / constty_wakeups_per_second, 524c9dba40cSEd Schouten constty_timeout, NULL); 525c9dba40cSEd Schouten } else { 526c9dba40cSEd Schouten /* Deallocate the constty buffer memory. */ 527c9dba40cSEd Schouten constty_clear(); 528c9dba40cSEd Schouten } 529c9dba40cSEd Schouten } 530c9dba40cSEd Schouten 531c9dba40cSEd Schouten static void 532c9dba40cSEd Schouten cn_drvinit(void *unused) 533c9dba40cSEd Schouten { 534c9dba40cSEd Schouten 535c9dba40cSEd Schouten mtx_init(&cnputs_mtx, "cnputs_mtx", NULL, MTX_SPIN | MTX_NOWITNESS); 536c9dba40cSEd Schouten use_cnputs_mtx = 1; 537c9dba40cSEd Schouten } 538c9dba40cSEd Schouten 539c9dba40cSEd Schouten SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL); 540c9dba40cSEd Schouten 541c9dba40cSEd Schouten /* 542c9dba40cSEd Schouten * Sysbeep(), if we have hardware for it 543c9dba40cSEd Schouten */ 544c9dba40cSEd Schouten 545c9dba40cSEd Schouten #ifdef HAS_TIMER_SPKR 546c9dba40cSEd Schouten 547c9dba40cSEd Schouten static int beeping; 548c9dba40cSEd Schouten 549c9dba40cSEd Schouten static void 550c9dba40cSEd Schouten sysbeepstop(void *chan) 551c9dba40cSEd Schouten { 552c9dba40cSEd Schouten 553c9dba40cSEd Schouten timer_spkr_release(); 554c9dba40cSEd Schouten beeping = 0; 555c9dba40cSEd Schouten } 556c9dba40cSEd Schouten 557c9dba40cSEd Schouten int 558c9dba40cSEd Schouten sysbeep(int pitch, int period) 559c9dba40cSEd Schouten { 560c9dba40cSEd Schouten 561c9dba40cSEd Schouten if (timer_spkr_acquire()) { 562c9dba40cSEd Schouten if (!beeping) { 563c9dba40cSEd Schouten /* Something else owns it. */ 564c9dba40cSEd Schouten return (EBUSY); 565c9dba40cSEd Schouten } 566c9dba40cSEd Schouten } 567c9dba40cSEd Schouten timer_spkr_setfreq(pitch); 568c9dba40cSEd Schouten if (!beeping) { 569c9dba40cSEd Schouten beeping = period; 570c9dba40cSEd Schouten timeout(sysbeepstop, (void *)NULL, period); 571c9dba40cSEd Schouten } 572c9dba40cSEd Schouten return (0); 573c9dba40cSEd Schouten } 574c9dba40cSEd Schouten 575c9dba40cSEd Schouten #else 576c9dba40cSEd Schouten 577c9dba40cSEd Schouten /* 578c9dba40cSEd Schouten * No hardware, no sound 579c9dba40cSEd Schouten */ 580c9dba40cSEd Schouten 581c9dba40cSEd Schouten int 582c9dba40cSEd Schouten sysbeep(int pitch __unused, int period __unused) 583c9dba40cSEd Schouten { 584c9dba40cSEd Schouten 585c9dba40cSEd Schouten return (ENODEV); 586c9dba40cSEd Schouten } 587c9dba40cSEd Schouten 588c9dba40cSEd Schouten #endif 589c9dba40cSEd Schouten 590