The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_cons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1988 University of Utah.
    5  * Copyright (c) 1991 The Regents of the University of California.
    6  * Copyright (c) 1999 Michael Smith
    7  * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    8  *
    9  * All rights reserved.
   10  *
   11  * This code is derived from software contributed to Berkeley by
   12  * the Systems Programming Group of the University of Utah Computer
   13  * Science Department.
   14  *
   15  * Redistribution and use in source and binary forms, with or without
   16  * modification, are permitted provided that the following conditions
   17  * are met:
   18  * 1. Redistributions of source code must retain the above copyright
   19  *    notice, this list of conditions and the following disclaimer.
   20  * 2. Redistributions in binary form must reproduce the above copyright
   21  *    notice, this list of conditions and the following disclaimer in the
   22  *    documentation and/or other materials provided with the distribution.
   23  * 3. Neither the name of the University nor the names of its contributors
   24  *    may be used to endorse or promote products derived from this software
   25  *    without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37  * SUCH DAMAGE.
   38  *
   39  *      from: @(#)cons.c        7.2 (Berkeley) 5/9/91
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD$");
   44 
   45 #include "opt_ddb.h"
   46 #include "opt_syscons.h"
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/lock.h>
   51 #include <sys/mutex.h>
   52 #include <sys/conf.h>
   53 #include <sys/cons.h>
   54 #include <sys/fcntl.h>
   55 #include <sys/kbio.h>
   56 #include <sys/kdb.h>
   57 #include <sys/kernel.h>
   58 #include <sys/malloc.h>
   59 #include <sys/msgbuf.h>
   60 #include <sys/namei.h>
   61 #include <sys/priv.h>
   62 #include <sys/proc.h>
   63 #include <sys/queue.h>
   64 #include <sys/reboot.h>
   65 #include <sys/sysctl.h>
   66 #include <sys/sbuf.h>
   67 #include <sys/tty.h>
   68 #include <sys/uio.h>
   69 #include <sys/vnode.h>
   70 
   71 #include <ddb/ddb.h>
   72 
   73 #include <dev/kbd/kbdreg.h>
   74 
   75 #include <machine/cpu.h>
   76 #include <machine/clock.h>
   77 
   78 static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
   79 
   80 struct cn_device {
   81         STAILQ_ENTRY(cn_device) cnd_next;
   82         struct          consdev *cnd_cn;
   83 };
   84 
   85 #define CNDEVPATHMAX    32
   86 #define CNDEVTAB_SIZE   4
   87 static struct cn_device cn_devtab[CNDEVTAB_SIZE];
   88 static STAILQ_HEAD(, cn_device) cn_devlist =
   89     STAILQ_HEAD_INITIALIZER(cn_devlist);
   90 
   91 int     cons_avail_mask = 0;    /* Bit mask. Each registered low level console
   92                                  * which is currently unavailable for inpit
   93                                  * (i.e., if it is in graphics mode) will have
   94                                  * this bit cleared.
   95                                  */
   96 
   97 static int cn_mute;
   98 SYSCTL_INT(_kern, OID_AUTO, consmute, CTLFLAG_RW, &cn_mute, 0,
   99     "State of the console muting");
  100 
  101 static char *consbuf;                   /* buffer used by `consmsgbuf' */
  102 static struct callout conscallout;      /* callout for outputting to constty */
  103 struct msgbuf consmsgbuf;               /* message buffer for console tty */
  104 static u_char console_pausing;          /* pause after each line during probe */
  105 static const char console_pausestr[] =
  106 "<pause; press any key to proceed to next line or '.' to end pause mode>";
  107 struct tty *constty;                    /* pointer to console "window" tty */
  108 static struct mtx constty_mtx;          /* Mutex for constty assignment. */
  109 MTX_SYSINIT(constty_mtx, &constty_mtx, "constty_mtx", MTX_DEF);
  110 static struct mtx cnputs_mtx;           /* Mutex for cnputs(). */
  111 MTX_SYSINIT(cnputs_mtx, &cnputs_mtx, "cnputs_mtx", MTX_SPIN | MTX_NOWITNESS);
  112 
  113 static void constty_timeout(void *arg);
  114 
  115 static struct consdev cons_consdev;
  116 DATA_SET(cons_set, cons_consdev);
  117 SET_DECLARE(cons_set, struct consdev);
  118 
  119 /*
  120  * Stub for configurations that don't actually have a keyboard driver. Inclusion
  121  * of kbd.c is contingent on any number of keyboard/console drivers being
  122  * present in the kernel; rather than trying to catch them all, we'll just
  123  * maintain this weak kbdinit that will be overridden by the strong version in
  124  * kbd.c if it's present.
  125  */
  126 __weak_symbol void
  127 kbdinit(void)
  128 {
  129 
  130 }
  131 
  132 void
  133 cninit(void)
  134 {
  135         struct consdev *best_cn, *cn, **list;
  136 
  137         /*
  138          * Check if we should mute the console (for security reasons perhaps)
  139          * It can be changes dynamically using sysctl kern.consmute
  140          * once we are up and going.
  141          * 
  142          */
  143         cn_mute = ((boothowto & (RB_MUTE
  144                         |RB_SINGLE
  145                         |RB_VERBOSE
  146                         |RB_ASKNAME)) == RB_MUTE);
  147 
  148         /*
  149          * Bring up the kbd layer just in time for cnprobe.  Console drivers
  150          * have a dependency on kbd being ready, so this fits nicely between the
  151          * machdep callers of cninit() and MI probing/initialization of consoles
  152          * here.
  153          */
  154         kbdinit();
  155 
  156         /*
  157          * Find the first console with the highest priority.
  158          */
  159         best_cn = NULL;
  160         SET_FOREACH(list, cons_set) {
  161                 cn = *list;
  162                 cnremove(cn);
  163                 /* Skip cons_consdev. */
  164                 if (cn->cn_ops == NULL)
  165                         continue;
  166                 cn->cn_ops->cn_probe(cn);
  167                 if (cn->cn_pri == CN_DEAD)
  168                         continue;
  169                 if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
  170                         best_cn = cn;
  171                 if (boothowto & RB_MULTIPLE) {
  172                         /*
  173                          * Initialize console, and attach to it.
  174                          */
  175                         cn->cn_ops->cn_init(cn);
  176                         cnadd(cn);
  177                 }
  178         }
  179         if (best_cn == NULL)
  180                 return;
  181         if ((boothowto & RB_MULTIPLE) == 0) {
  182                 best_cn->cn_ops->cn_init(best_cn);
  183                 cnadd(best_cn);
  184         }
  185         if (boothowto & RB_PAUSE)
  186                 console_pausing = 1;
  187         /*
  188          * Make the best console the preferred console.
  189          */
  190         cnselect(best_cn);
  191 
  192 #ifdef EARLY_PRINTF
  193         /*
  194          * Release early console.
  195          */
  196         early_putc = NULL;
  197 #endif
  198 }
  199 
  200 void
  201 cninit_finish(void)
  202 {
  203         console_pausing = 0;
  204 } 
  205 
  206 /* add a new physical console to back the virtual console */
  207 int
  208 cnadd(struct consdev *cn)
  209 {
  210         struct cn_device *cnd;
  211         int i;
  212 
  213         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  214                 if (cnd->cnd_cn == cn)
  215                         return (0);
  216         for (i = 0; i < CNDEVTAB_SIZE; i++) {
  217                 cnd = &cn_devtab[i];
  218                 if (cnd->cnd_cn == NULL)
  219                         break;
  220         }
  221         if (cnd->cnd_cn != NULL)
  222                 return (ENOMEM);
  223         cnd->cnd_cn = cn;
  224         if (cn->cn_name[0] == '\0') {
  225                 /* XXX: it is unclear if/where this print might output */
  226                 printf("WARNING: console at %p has no name\n", cn);
  227         }
  228         STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
  229         if (STAILQ_FIRST(&cn_devlist) == cnd)
  230                 ttyconsdev_select(cnd->cnd_cn->cn_name);
  231 
  232         /* Add device to the active mask. */
  233         cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0);
  234 
  235         return (0);
  236 }
  237 
  238 void
  239 cnremove(struct consdev *cn)
  240 {
  241         struct cn_device *cnd;
  242         int i;
  243 
  244         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  245                 if (cnd->cnd_cn != cn)
  246                         continue;
  247                 if (STAILQ_FIRST(&cn_devlist) == cnd)
  248                         ttyconsdev_select(NULL);
  249                 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
  250                 cnd->cnd_cn = NULL;
  251 
  252                 /* Remove this device from available mask. */
  253                 for (i = 0; i < CNDEVTAB_SIZE; i++) 
  254                         if (cnd == &cn_devtab[i]) {
  255                                 cons_avail_mask &= ~(1 << i);
  256                                 break;
  257                         }
  258 #if 0
  259                 /*
  260                  * XXX
  261                  * syscons gets really confused if console resources are
  262                  * freed after the system has initialized.
  263                  */
  264                 if (cn->cn_term != NULL)
  265                         cn->cn_ops->cn_term(cn);
  266 #endif
  267                 return;
  268         }
  269 }
  270 
  271 void
  272 cnselect(struct consdev *cn)
  273 {
  274         struct cn_device *cnd;
  275 
  276         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  277                 if (cnd->cnd_cn != cn)
  278                         continue;
  279                 if (cnd == STAILQ_FIRST(&cn_devlist))
  280                         return;
  281                 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
  282                 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
  283                 ttyconsdev_select(cnd->cnd_cn->cn_name);
  284                 return;
  285         }
  286 }
  287 
  288 void
  289 cnavailable(struct consdev *cn, int available)
  290 {
  291         int i;
  292 
  293         for (i = 0; i < CNDEVTAB_SIZE; i++) {
  294                 if (cn_devtab[i].cnd_cn == cn)
  295                         break;
  296         }
  297         if (available) {
  298                 if (i < CNDEVTAB_SIZE)
  299                         cons_avail_mask |= (1 << i); 
  300                 cn->cn_flags &= ~CN_FLAG_NOAVAIL;
  301         } else {
  302                 if (i < CNDEVTAB_SIZE)
  303                         cons_avail_mask &= ~(1 << i);
  304                 cn->cn_flags |= CN_FLAG_NOAVAIL;
  305         }
  306 }
  307 
  308 int
  309 cnunavailable(void)
  310 {
  311 
  312         return (cons_avail_mask == 0);
  313 }
  314 
  315 /*
  316  * sysctl_kern_console() provides output parseable in conscontrol(1).
  317  */
  318 static int
  319 sysctl_kern_console(SYSCTL_HANDLER_ARGS)
  320 {
  321         struct cn_device *cnd;
  322         struct consdev *cp, **list;
  323         char *p;
  324         int delete, error;
  325         struct sbuf *sb;
  326 
  327         sb = sbuf_new(NULL, NULL, CNDEVPATHMAX * 2, SBUF_AUTOEXTEND |
  328             SBUF_INCLUDENUL);
  329         if (sb == NULL)
  330                 return (ENOMEM);
  331         sbuf_clear(sb);
  332         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  333                 sbuf_printf(sb, "%s,", cnd->cnd_cn->cn_name);
  334         sbuf_printf(sb, "/");
  335         SET_FOREACH(list, cons_set) {
  336                 cp = *list;
  337                 if (cp->cn_name[0] != '\0')
  338                         sbuf_printf(sb, "%s,", cp->cn_name);
  339         }
  340         sbuf_finish(sb);
  341         error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req);
  342         if (error == 0 && req->newptr != NULL) {
  343                 p = sbuf_data(sb);
  344                 error = ENXIO;
  345                 delete = 0;
  346                 if (*p == '-') {
  347                         delete = 1;
  348                         p++;
  349                 }
  350                 SET_FOREACH(list, cons_set) {
  351                         cp = *list;
  352                         if (strcmp(p, cp->cn_name) != 0)
  353                                 continue;
  354                         if (delete) {
  355                                 cnremove(cp);
  356                                 error = 0;
  357                         } else {
  358                                 error = cnadd(cp);
  359                                 if (error == 0)
  360                                         cnselect(cp);
  361                         }
  362                         break;
  363                 }
  364         }
  365         sbuf_delete(sb);
  366         return (error);
  367 }
  368 
  369 SYSCTL_PROC(_kern, OID_AUTO, console,
  370     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, 0,
  371     sysctl_kern_console, "A",
  372     "Console device control");
  373 
  374 void
  375 cngrab(void)
  376 {
  377         struct cn_device *cnd;
  378         struct consdev *cn;
  379 
  380         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  381                 cn = cnd->cnd_cn;
  382                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
  383                         cn->cn_ops->cn_grab(cn);
  384         }
  385 }
  386 
  387 void
  388 cnungrab(void)
  389 {
  390         struct cn_device *cnd;
  391         struct consdev *cn;
  392 
  393         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  394                 cn = cnd->cnd_cn;
  395                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG))
  396                         cn->cn_ops->cn_ungrab(cn);
  397         }
  398 }
  399 
  400 void
  401 cnresume(void)
  402 {
  403         struct cn_device *cnd;
  404         struct consdev *cn;
  405 
  406         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  407                 cn = cnd->cnd_cn;
  408                 if (cn->cn_ops->cn_resume != NULL)
  409                         cn->cn_ops->cn_resume(cn);
  410         }
  411 }
  412 
  413 /*
  414  * Low level console routines.
  415  */
  416 int
  417 cngetc(void)
  418 {
  419         int c;
  420 
  421         if (cn_mute)
  422                 return (-1);
  423         while ((c = cncheckc()) == -1)
  424                 cpu_spinwait();
  425         if (c == '\r')
  426                 c = '\n';               /* console input is always ICRNL */
  427         return (c);
  428 }
  429 
  430 int
  431 cncheckc(void)
  432 {
  433         struct cn_device *cnd;
  434         struct consdev *cn;
  435         int c;
  436 
  437         if (cn_mute)
  438                 return (-1);
  439         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  440                 cn = cnd->cnd_cn;
  441                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
  442                         c = cn->cn_ops->cn_getc(cn);
  443                         if (c != -1)
  444                                 return (c);
  445                 }
  446         }
  447         return (-1);
  448 }
  449 
  450 void
  451 cngets(char *cp, size_t size, int visible)
  452 {
  453         char *lp, *end;
  454         int c;
  455 
  456         cngrab();
  457 
  458         lp = cp;
  459         end = cp + size - 1;
  460         for (;;) {
  461                 c = cngetc() & 0177;
  462                 switch (c) {
  463                 case '\n':
  464                 case '\r':
  465                         cnputc(c);
  466                         *lp = '\0';
  467                         cnungrab();
  468                         return;
  469                 case '\b':
  470                 case '\177':
  471                         if (lp > cp) {
  472                                 if (visible)
  473                                         cnputs("\b \b");
  474                                 lp--;
  475                         }
  476                         continue;
  477                 case '\0':
  478                         continue;
  479                 default:
  480                         if (lp < end) {
  481                                 switch (visible) {
  482                                 case GETS_NOECHO:
  483                                         break;
  484                                 case GETS_ECHOPASS:
  485                                         cnputc('*');
  486                                         break;
  487                                 default:
  488                                         cnputc(c);
  489                                         break;
  490                                 }
  491                                 *lp++ = c;
  492                         }
  493                 }
  494         }
  495 }
  496 
  497 void
  498 cnputc(int c)
  499 {
  500         struct cn_device *cnd;
  501         struct consdev *cn;
  502         const char *cp;
  503 
  504 #ifdef EARLY_PRINTF
  505         if (early_putc != NULL) {
  506                 if (c == '\n')
  507                         early_putc('\r');
  508                 early_putc(c);
  509                 return;
  510         }
  511 #endif
  512 
  513         if (cn_mute || c == '\0')
  514                 return;
  515         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  516                 cn = cnd->cnd_cn;
  517                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
  518                         if (c == '\n')
  519                                 cn->cn_ops->cn_putc(cn, '\r');
  520                         cn->cn_ops->cn_putc(cn, c);
  521                 }
  522         }
  523         if (console_pausing && c == '\n' && !kdb_active) {
  524                 for (cp = console_pausestr; *cp != '\0'; cp++)
  525                         cnputc(*cp);
  526                 cngrab();
  527                 if (cngetc() == '.')
  528                         console_pausing = 0;
  529                 cnungrab();
  530                 cnputc('\r');
  531                 for (cp = console_pausestr; *cp != '\0'; cp++)
  532                         cnputc(' ');
  533                 cnputc('\r');
  534         }
  535 }
  536 
  537 void
  538 cnputsn(const char *p, size_t n)
  539 {
  540         size_t i;
  541         int unlock_reqd = 0;
  542 
  543         if (mtx_initialized(&cnputs_mtx)) {
  544                 /*
  545                  * NOTE: Debug prints and/or witness printouts in
  546                  * console driver clients can cause the "cnputs_mtx"
  547                  * mutex to recurse. Simply return if that happens.
  548                  */
  549                 if (mtx_owned(&cnputs_mtx))
  550                         return;
  551                 mtx_lock_spin(&cnputs_mtx);
  552                 unlock_reqd = 1;
  553         }
  554 
  555         for (i = 0; i < n; i++)
  556                 cnputc(p[i]);
  557 
  558         if (unlock_reqd)
  559                 mtx_unlock_spin(&cnputs_mtx);
  560 }
  561 
  562 void
  563 cnputs(const char *p)
  564 {
  565         cnputsn(p, strlen(p));
  566 }
  567 
  568 static unsigned int consmsgbuf_size = 65536;
  569 SYSCTL_UINT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RWTUN, &consmsgbuf_size,
  570     0, "Console tty buffer size");
  571 
  572 /*
  573  * Redirect console output to a tty.
  574  */
  575 int
  576 constty_set(struct tty *tp)
  577 {
  578         int size = consmsgbuf_size;
  579         void *buf = NULL;
  580 
  581         tty_assert_locked(tp);
  582         if (constty == tp)
  583                 return (0);
  584         if (constty != NULL)
  585                 return (EBUSY);
  586 
  587         if (consbuf == NULL) {
  588                 tty_unlock(tp);
  589                 buf = malloc(size, M_TTYCONS, M_WAITOK);
  590                 tty_lock(tp);
  591         }
  592         mtx_lock(&constty_mtx);
  593         if (constty != NULL) {
  594                 mtx_unlock(&constty_mtx);
  595                 free(buf, M_TTYCONS);
  596                 return (EBUSY);
  597         }
  598         if (consbuf == NULL) {
  599                 consbuf = buf;
  600                 msgbuf_init(&consmsgbuf, buf, size);
  601         } else
  602                 free(buf, M_TTYCONS);
  603         constty = tp;
  604         mtx_unlock(&constty_mtx);
  605 
  606         callout_init_mtx(&conscallout, tty_getlock(tp), 0);
  607         constty_timeout(tp);
  608         return (0);
  609 }
  610 
  611 /*
  612  * Disable console redirection to a tty.
  613  */
  614 int
  615 constty_clear(struct tty *tp)
  616 {
  617         int c;
  618 
  619         tty_assert_locked(tp);
  620         if (constty != tp)
  621                 return (ENXIO);
  622         callout_stop(&conscallout);
  623         mtx_lock(&constty_mtx);
  624         constty = NULL;
  625         mtx_unlock(&constty_mtx);
  626         while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
  627                 cnputc(c);
  628         /* We never free consbuf because it can still be in use. */
  629         return (0);
  630 }
  631 
  632 /* Times per second to check for pending console tty messages. */
  633 static int constty_wakeups_per_second = 15;
  634 SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
  635     &constty_wakeups_per_second, 0,
  636     "Times per second to check for pending console tty messages");
  637 
  638 static void
  639 constty_timeout(void *arg)
  640 {
  641         struct tty *tp = arg;
  642         int c;
  643 
  644         tty_assert_locked(tp);
  645         while ((c = msgbuf_getchar(&consmsgbuf)) != -1) {
  646                 if (tty_putchar(tp, c) < 0) {
  647                         constty_clear(tp);
  648                         return;
  649                 }
  650         }
  651         callout_reset_sbt(&conscallout, SBT_1S / constty_wakeups_per_second,
  652             0, constty_timeout, tp, C_PREL(1));
  653 }
  654 
  655 /*
  656  * Sysbeep(), if we have hardware for it
  657  */
  658 
  659 #ifdef HAS_TIMER_SPKR
  660 
  661 static bool beeping;
  662 static struct callout beeping_timer;
  663 
  664 static void
  665 sysbeepstop(void *chan)
  666 {
  667 
  668         timer_spkr_release();
  669         beeping = false;
  670 }
  671 
  672 int
  673 sysbeep(int pitch, sbintime_t duration)
  674 {
  675 
  676         if (timer_spkr_acquire()) {
  677                 if (!beeping) {
  678                         /* Something else owns it. */
  679                         return (EBUSY);
  680                 }
  681         }
  682         timer_spkr_setfreq(pitch);
  683         if (!beeping) {
  684                 beeping = true;
  685                 callout_reset_sbt(&beeping_timer, duration, 0, sysbeepstop,
  686                     NULL, C_PREL(5));
  687         }
  688         return (0);
  689 }
  690 
  691 static void
  692 sysbeep_init(void *unused)
  693 {
  694 
  695         callout_init(&beeping_timer, 1);
  696 }
  697 SYSINIT(sysbeep, SI_SUB_SOFTINTR, SI_ORDER_ANY, sysbeep_init, NULL);
  698 #else
  699 
  700 /*
  701  * No hardware, no sound
  702  */
  703 
  704 int
  705 sysbeep(int pitch __unused, sbintime_t duration __unused)
  706 {
  707 
  708         return (ENODEV);
  709 }
  710 
  711 #endif
  712 
  713 /*
  714  * Temporary support for sc(4) to vt(4) transition.
  715  */
  716 static unsigned vty_prefer;
  717 static char vty_name[16];
  718 SYSCTL_STRING(_kern, OID_AUTO, vty, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, vty_name,
  719     0, "Console vty driver");
  720 
  721 int
  722 vty_enabled(unsigned vty)
  723 {
  724         static unsigned vty_selected = 0;
  725 
  726         if (vty_selected == 0) {
  727                 TUNABLE_STR_FETCH("kern.vty", vty_name, sizeof(vty_name));
  728                 do {
  729 #if defined(DEV_SC)
  730                         if (strcmp(vty_name, "sc") == 0) {
  731                                 vty_selected = VTY_SC;
  732                                 break;
  733                         }
  734 #endif
  735 #if defined(DEV_VT)
  736                         if (strcmp(vty_name, "vt") == 0) {
  737                                 vty_selected = VTY_VT;
  738                                 break;
  739                         }
  740 #endif
  741                         if (vty_prefer != 0) {
  742                                 vty_selected = vty_prefer;
  743                                 break;
  744                         }
  745 #if defined(DEV_VT)
  746                         vty_selected = VTY_VT;
  747 #elif defined(DEV_SC)
  748                         vty_selected = VTY_SC;
  749 #endif
  750                 } while (0);
  751 
  752                 if (vty_selected == VTY_VT)
  753                         strcpy(vty_name, "vt");
  754                 else if (vty_selected == VTY_SC)
  755                         strcpy(vty_name, "sc");
  756         }
  757         return ((vty_selected & vty) != 0);
  758 }
  759 
  760 void
  761 vty_set_preferred(unsigned vty)
  762 {
  763 
  764         vty_prefer = vty;
  765 #if !defined(DEV_SC)
  766         vty_prefer &= ~VTY_SC;
  767 #endif
  768 #if !defined(DEV_VT)
  769         vty_prefer &= ~VTY_VT;
  770 #endif
  771 }

Cache object: 2393befa7d84a4520d02cee3580a054a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.