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/tty_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  * 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  * 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.
   21  *
   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
   32  * SUCH DAMAGE.
   33  *
   34  *      from: @(#)cons.c        7.2 (Berkeley) 5/9/91
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/5.3/sys/kern/tty_cons.c 136588 2004-10-16 08:43:07Z cvs2svn $");
   39 
   40 #include "opt_ddb.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/conf.h>
   45 #include <sys/cons.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/kdb.h>
   48 #include <sys/kernel.h>
   49 #include <sys/malloc.h>
   50 #include <sys/msgbuf.h>
   51 #include <sys/namei.h>
   52 #include <sys/proc.h>
   53 #include <sys/queue.h>
   54 #include <sys/reboot.h>
   55 #include <sys/sysctl.h>
   56 #include <sys/tty.h>
   57 #include <sys/uio.h>
   58 #include <sys/vnode.h>
   59 
   60 #include <ddb/ddb.h>
   61 
   62 #include <machine/cpu.h>
   63 
   64 static  d_open_t        cnopen;
   65 static  d_close_t       cnclose;
   66 static  d_read_t        cnread;
   67 static  d_write_t       cnwrite;
   68 static  d_ioctl_t       cnioctl;
   69 static  d_poll_t        cnpoll;
   70 static  d_kqfilter_t    cnkqfilter;
   71 
   72 /*
   73  * XXX: We really want major #0, but zero here means
   74  * XXX: allocate a major number automatically.
   75  * XXX: kern_conf.c knows what to do when it sees 256.
   76  */
   77 static struct cdevsw cn_cdevsw = {
   78         .d_version =    D_VERSION,
   79         .d_open =       cnopen,
   80         .d_close =      cnclose,
   81         .d_read =       cnread,
   82         .d_write =      cnwrite,
   83         .d_ioctl =      cnioctl,
   84         .d_poll =       cnpoll,
   85         .d_name =       "console",
   86         .d_maj =        256,
   87         .d_flags =      D_TTY | D_NEEDGIANT,
   88         .d_kqfilter =   cnkqfilter,
   89 };
   90 
   91 struct cn_device {
   92         STAILQ_ENTRY(cn_device) cnd_next;
   93         struct          vnode *cnd_vp;
   94         struct          consdev *cnd_cn;
   95 };
   96 
   97 #define CNDEVPATHMAX    32
   98 #define CNDEVTAB_SIZE   4
   99 static struct cn_device cn_devtab[CNDEVTAB_SIZE];
  100 static STAILQ_HEAD(, cn_device) cn_devlist =
  101     STAILQ_HEAD_INITIALIZER(cn_devlist);
  102 
  103 #define CND_INVALID(cnd, td)                                            \
  104         (cnd == NULL || cnd->cnd_vp == NULL ||                          \
  105             (cnd->cnd_vp->v_type == VBAD && !cn_devopen(cnd, td, 1)))
  106 
  107 static dev_t    cn_udev_t;
  108 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
  109         &cn_udev_t, sizeof cn_udev_t, "T,struct cdev *", "");
  110 
  111 int     cons_avail_mask = 0;    /* Bit mask. Each registered low level console
  112                                  * which is currently unavailable for inpit
  113                                  * (i.e., if it is in graphics mode) will have
  114                                  * this bit cleared.
  115                                  */
  116 static int cn_mute;
  117 static int openflag;                    /* how /dev/console was opened */
  118 static int cn_is_open;
  119 static char *consbuf;                   /* buffer used by `consmsgbuf' */
  120 static struct callout conscallout;      /* callout for outputting to constty */
  121 struct msgbuf consmsgbuf;               /* message buffer for console tty */
  122 static u_char console_pausing;          /* pause after each line during probe */
  123 static char *console_pausestr=
  124 "<pause; press any key to proceed to next line or '.' to end pause mode>";
  125 struct tty *constty;                    /* pointer to console "window" tty */
  126 
  127 static void constty_timeout(void *arg);
  128 
  129 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  130 SET_DECLARE(cons_set, struct consdev);
  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
  147                         |RB_CONFIG)) == RB_MUTE);
  148 
  149         /*
  150          * Find the first console with the highest priority.
  151          */
  152         best_cn = NULL;
  153         SET_FOREACH(list, cons_set) {
  154                 cn = *list;
  155                 cnremove(cn);
  156                 if (cn->cn_probe == NULL)
  157                         continue;
  158                 cn->cn_probe(cn);
  159                 if (cn->cn_pri == CN_DEAD)
  160                         continue;
  161                 if (best_cn == NULL || cn->cn_pri > best_cn->cn_pri)
  162                         best_cn = cn;
  163                 if (boothowto & RB_MULTIPLE) {
  164                         /*
  165                          * Initialize console, and attach to it.
  166                          */
  167                         cnadd(cn);
  168                         cn->cn_init(cn);
  169                 }
  170         }
  171         if (best_cn == NULL)
  172                 return;
  173         if ((boothowto & RB_MULTIPLE) == 0) {
  174                 cnadd(best_cn);
  175                 best_cn->cn_init(best_cn);
  176         }
  177         if (boothowto & RB_PAUSE)
  178                 console_pausing = 1;
  179         /*
  180          * Make the best console the preferred console.
  181          */
  182         cnselect(best_cn);
  183 }
  184 
  185 void
  186 cninit_finish()
  187 {
  188         console_pausing = 0;
  189 } 
  190 
  191 /* add a new physical console to back the virtual console */
  192 int
  193 cnadd(struct consdev *cn)
  194 {
  195         struct cn_device *cnd;
  196         int i;
  197 
  198         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  199                 if (cnd->cnd_cn == cn)
  200                         return (0);
  201         for (i = 0; i < CNDEVTAB_SIZE; i++) {
  202                 cnd = &cn_devtab[i];
  203                 if (cnd->cnd_cn == NULL)
  204                         break;
  205         }
  206         if (cnd->cnd_cn != NULL)
  207                 return (ENOMEM);
  208         cnd->cnd_cn = cn;
  209         if (cn->cn_name[0] == '\0') {
  210                 /* XXX: it is unclear if/where this print might output */
  211                 printf("WARNING: console at %p has no name\n", cn);
  212         }
  213         STAILQ_INSERT_TAIL(&cn_devlist, cnd, cnd_next);
  214 
  215         /* Add device to the active mask. */
  216         cnavailable(cn, (cn->cn_flags & CN_FLAG_NOAVAIL) == 0);
  217 
  218         return (0);
  219 }
  220 
  221 void
  222 cnremove(struct consdev *cn)
  223 {
  224         struct cn_device *cnd;
  225         int i;
  226 
  227         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  228                 if (cnd->cnd_cn != cn)
  229                         continue;
  230                 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
  231                 if (cnd->cnd_vp != NULL)
  232                         vn_close(cnd->cnd_vp, openflag, NOCRED, NULL);
  233                 cnd->cnd_vp = NULL;
  234                 cnd->cnd_cn = NULL;
  235 
  236                 /* Remove this device from available mask. */
  237                 for (i = 0; i < CNDEVTAB_SIZE; i++) 
  238                         if (cnd == &cn_devtab[i]) {
  239                                 cons_avail_mask &= ~(1 << i);
  240                                 break;
  241                         }
  242 #if 0
  243                 /*
  244                  * XXX
  245                  * syscons gets really confused if console resources are
  246                  * freed after the system has initialized.
  247                  */
  248                 if (cn->cn_term != NULL)
  249                         cn->cn_term(cn);
  250 #endif
  251                 return;
  252         }
  253 }
  254 
  255 void
  256 cnselect(struct consdev *cn)
  257 {
  258         struct cn_device *cnd;
  259 
  260         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  261                 if (cnd->cnd_cn != cn)
  262                         continue;
  263                 if (cnd == STAILQ_FIRST(&cn_devlist))
  264                         return;
  265                 STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
  266                 STAILQ_INSERT_HEAD(&cn_devlist, cnd, cnd_next);
  267                 return;
  268         }
  269 }
  270 
  271 void
  272 cnavailable(struct consdev *cn, int available)
  273 {
  274         int i;
  275 
  276         for (i = 0; i < CNDEVTAB_SIZE; i++) {
  277                 if (cn_devtab[i].cnd_cn == cn)
  278                         break;
  279         }
  280         if (available) {
  281                 if (i < CNDEVTAB_SIZE)
  282                         cons_avail_mask |= (1 << i); 
  283                 cn->cn_flags &= ~CN_FLAG_NOAVAIL;
  284         } else {
  285                 if (i < CNDEVTAB_SIZE)
  286                         cons_avail_mask &= ~(1 << i);
  287                 cn->cn_flags |= CN_FLAG_NOAVAIL;
  288         }
  289 }
  290 
  291 int
  292 cnunavailable(void)
  293 {
  294 
  295         return (cons_avail_mask == 0);
  296 }
  297 
  298 /*
  299  * XXX: rewrite to use sbufs instead
  300  */
  301 
  302 static int
  303 sysctl_kern_console(SYSCTL_HANDLER_ARGS)
  304 {
  305         struct cn_device *cnd;
  306         struct consdev *cp, **list;
  307         char *name, *p;
  308         int delete, len, error;
  309 
  310         len = 2;
  311         SET_FOREACH(list, cons_set) {
  312                 cp = *list;
  313                 if (cp->cn_name[0] != '\0')
  314                         len += strlen(cp->cn_name) + 1;
  315         }
  316         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  317                 len += strlen(cnd->cnd_cn->cn_name) + 1;
  318         len = len > CNDEVPATHMAX ? len : CNDEVPATHMAX;
  319         MALLOC(name, char *, len, M_TEMP, M_WAITOK | M_ZERO);
  320         p = name;
  321         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  322                 p += sprintf(p, "%s,", cnd->cnd_cn->cn_name);
  323         *p++ = '/';
  324         SET_FOREACH(list, cons_set) {
  325                 cp = *list;
  326                 if (cp->cn_name[0] != '\0')
  327                         p += sprintf(p, "%s,", cp->cn_name);
  328         }
  329         error = sysctl_handle_string(oidp, name, len, req);
  330         if (error == 0 && req->newptr != NULL) {
  331                 p = name;
  332                 error = ENXIO;
  333                 delete = 0;
  334                 if (*p == '-') {
  335                         delete = 1;
  336                         p++;
  337                 }
  338                 SET_FOREACH(list, cons_set) {
  339                         cp = *list;
  340                         if (strcmp(p, cp->cn_name) != 0)
  341                                 continue;
  342                         if (delete) {
  343                                 cnremove(cp);
  344                                 error = 0;
  345                         } else {
  346                                 error = cnadd(cp);
  347                                 if (error == 0)
  348                                         cnselect(cp);
  349                         }
  350                         break;
  351                 }
  352         }
  353         FREE(name, M_TEMP);
  354         return (error);
  355 }
  356 
  357 SYSCTL_PROC(_kern, OID_AUTO, console, CTLTYPE_STRING|CTLFLAG_RW,
  358         0, 0, sysctl_kern_console, "A", "Console device control");
  359 
  360 /*
  361  * User has changed the state of the console muting.
  362  * This may require us to open or close the device in question.
  363  */
  364 static int
  365 sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
  366 {
  367         int error;
  368         int ocn_mute;
  369 
  370         ocn_mute = cn_mute;
  371         error = sysctl_handle_int(oidp, &cn_mute, 0, req);
  372         if (error != 0 || req->newptr == NULL)
  373                 return (error);
  374         if (ocn_mute && !cn_mute && cn_is_open)
  375                 error = cnopen(NULL, openflag, 0, curthread);
  376         else if (!ocn_mute && cn_mute && cn_is_open) {
  377                 error = cnclose(NULL, openflag, 0, curthread);
  378                 cn_is_open = 1;         /* XXX hack */
  379         }
  380         return (error);
  381 }
  382 
  383 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
  384         0, sizeof(cn_mute), sysctl_kern_consmute, "I", "");
  385 
  386 static int
  387 cn_devopen(struct cn_device *cnd, struct thread *td, int forceopen)
  388 {
  389         char path[CNDEVPATHMAX];
  390         struct nameidata nd;
  391         struct vnode *vp;
  392         struct cdev *dev;
  393         int error;
  394 
  395         if ((vp = cnd->cnd_vp) != NULL) {
  396                 if (!forceopen && vp->v_type != VBAD) {
  397                         dev = vp->v_rdev;
  398                         return ((*devsw(dev)->d_open)(dev, openflag, 0, td));
  399                 }
  400                 cnd->cnd_vp = NULL;
  401                 vn_close(vp, openflag, td->td_ucred, td);
  402         }
  403         snprintf(path, sizeof(path), "/dev/%s", cnd->cnd_cn->cn_name);
  404         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
  405         error = vn_open(&nd, &openflag, 0, -1);
  406         if (error == 0) {
  407                 NDFREE(&nd, NDF_ONLY_PNBUF);
  408                 VOP_UNLOCK(nd.ni_vp, 0, td);
  409                 if (nd.ni_vp->v_type == VCHR)
  410                         cnd->cnd_vp = nd.ni_vp;
  411                 else
  412                         vn_close(nd.ni_vp, openflag, td->td_ucred, td);
  413         }
  414         return (cnd->cnd_vp != NULL);
  415 }
  416 
  417 static int
  418 cnopen(struct cdev *dev, int flag, int mode, struct thread *td)
  419 {
  420         struct cn_device *cnd;
  421 
  422         openflag = flag | FWRITE;       /* XXX */
  423         cn_is_open = 1;                 /* console is logically open */
  424         if (cn_mute)
  425                 return (0);
  426         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next)
  427                 cn_devopen(cnd, td, 0);
  428         return (0);
  429 }
  430 
  431 static int
  432 cnclose(struct cdev *dev, int flag, int mode, struct thread *td)
  433 {
  434         struct cn_device *cnd;
  435         struct vnode *vp;
  436 
  437         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  438                 if ((vp = cnd->cnd_vp) == NULL)
  439                         continue; 
  440                 cnd->cnd_vp = NULL;
  441                 vn_close(vp, openflag, td->td_ucred, td);
  442         }
  443         cn_is_open = 0;
  444         return (0);
  445 }
  446 
  447 static int
  448 cnread(struct cdev *dev, struct uio *uio, int flag)
  449 {
  450         struct cn_device *cnd;
  451 
  452         cnd = STAILQ_FIRST(&cn_devlist);
  453         if (cn_mute || CND_INVALID(cnd, curthread))
  454                 return (0);
  455         dev = cnd->cnd_vp->v_rdev;
  456         return ((*devsw(dev)->d_read)(dev, uio, flag));
  457 }
  458 
  459 static int
  460 cnwrite(struct cdev *dev, struct uio *uio, int flag)
  461 {
  462         struct cn_device *cnd;
  463 
  464         cnd = STAILQ_FIRST(&cn_devlist);
  465         if (cn_mute || CND_INVALID(cnd, curthread))
  466                 goto done;
  467         if (constty)
  468                 dev = constty->t_dev;
  469         else
  470                 dev = cnd->cnd_vp->v_rdev;
  471         if (dev != NULL) {
  472                 log_console(uio);
  473                 return ((*devsw(dev)->d_write)(dev, uio, flag));
  474         }
  475 done:
  476         uio->uio_resid = 0; /* dump the data */
  477         return (0);
  478 }
  479 
  480 static int
  481 cnioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  482 {
  483         struct cn_device *cnd;
  484         int error;
  485 
  486         cnd = STAILQ_FIRST(&cn_devlist);
  487         if (cn_mute || CND_INVALID(cnd, td))
  488                 return (0);
  489         /*
  490          * Superuser can always use this to wrest control of console
  491          * output from the "virtual" console.
  492          */
  493         if (cmd == TIOCCONS && constty) {
  494                 error = suser(td);
  495                 if (error)
  496                         return (error);
  497                 constty = NULL;
  498                 return (0);
  499         }
  500         dev = cnd->cnd_vp->v_rdev;
  501         if (dev != NULL)
  502                 return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
  503         return (0);
  504 }
  505 
  506 /*
  507  * XXX
  508  * poll/kqfilter do not appear to be correct
  509  */
  510 static int
  511 cnpoll(struct cdev *dev, int events, struct thread *td)
  512 {
  513         struct cn_device *cnd;
  514 
  515         cnd = STAILQ_FIRST(&cn_devlist);
  516         if (cn_mute || CND_INVALID(cnd, td))
  517                 return (0);
  518         dev = cnd->cnd_vp->v_rdev;
  519         if (dev != NULL)
  520                 return ((*devsw(dev)->d_poll)(dev, events, td));
  521         return (0);
  522 }
  523 
  524 static int
  525 cnkqfilter(struct cdev *dev, struct knote *kn)
  526 {
  527         struct cn_device *cnd;
  528 
  529         cnd = STAILQ_FIRST(&cn_devlist);
  530         if (cn_mute || CND_INVALID(cnd, curthread))
  531                 return (EINVAL);
  532         dev = cnd->cnd_vp->v_rdev;
  533         if (dev != NULL)
  534                 return ((*devsw(dev)->d_kqfilter)(dev, kn));
  535         return (ENXIO);
  536 }
  537 
  538 /*
  539  * Low level console routines.
  540  */
  541 int
  542 cngetc(void)
  543 {
  544         int c;
  545 
  546         if (cn_mute)
  547                 return (-1);
  548         while ((c = cncheckc()) == -1)
  549                 ;
  550         if (c == '\r')
  551                 c = '\n';               /* console input is always ICRNL */
  552         return (c);
  553 }
  554 
  555 int
  556 cncheckc(void)
  557 {
  558         struct cn_device *cnd;
  559         struct consdev *cn;
  560         int c;
  561 
  562         if (cn_mute)
  563                 return (-1);
  564         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  565                 cn = cnd->cnd_cn;
  566                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
  567                         c = cn->cn_checkc(cn);
  568                         if (c != -1) {
  569                                 return (c);
  570                         }
  571                 }
  572         }
  573         return (-1);
  574 }
  575 
  576 void
  577 cnputc(int c)
  578 {
  579         struct cn_device *cnd;
  580         struct consdev *cn;
  581         char *cp;
  582 
  583         if (cn_mute || c == '\0')
  584                 return;
  585         STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  586                 cn = cnd->cnd_cn;
  587                 if (!kdb_active || !(cn->cn_flags & CN_FLAG_NODEBUG)) {
  588                         if (c == '\n')
  589                                 cn->cn_putc(cn, '\r');
  590                         cn->cn_putc(cn, c);
  591                 }
  592         }
  593         if (console_pausing && c == '\n' && !kdb_active) {
  594                 for (cp = console_pausestr; *cp != '\0'; cp++)
  595                         cnputc(*cp);
  596                 if (cngetc() == '.')
  597                         console_pausing = 0;
  598                 cnputc('\r');
  599                 for (cp = console_pausestr; *cp != '\0'; cp++)
  600                         cnputc(' ');
  601                 cnputc('\r');
  602         }
  603 }
  604 
  605 void
  606 cndbctl(int on)
  607 {
  608         struct cn_device *cnd;
  609         struct consdev *cn;
  610         static int refcount;
  611 
  612         if (!on)
  613                 refcount--;
  614         if (refcount == 0)
  615                 STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
  616                         cn = cnd->cnd_cn;
  617                         if (cn->cn_dbctl != NULL)
  618                                 cn->cn_dbctl(cn, on);
  619                 }
  620         if (on)
  621                 refcount++;
  622 }
  623 
  624 static int consmsgbuf_size = 8192;
  625 SYSCTL_INT(_kern, OID_AUTO, consmsgbuf_size, CTLFLAG_RW, &consmsgbuf_size, 0,
  626     "");
  627 
  628 /*
  629  * Redirect console output to a tty.
  630  */
  631 void
  632 constty_set(struct tty *tp)
  633 {
  634         int size;
  635 
  636         KASSERT(tp != NULL, ("constty_set: NULL tp"));
  637         if (consbuf == NULL) {
  638                 size = consmsgbuf_size;
  639                 consbuf = malloc(size, M_TTYS, M_WAITOK);
  640                 msgbuf_init(&consmsgbuf, consbuf, size);
  641                 callout_init(&conscallout, 0);
  642         }
  643         constty = tp;
  644         constty_timeout(NULL);
  645 }
  646 
  647 /*
  648  * Disable console redirection to a tty.
  649  */
  650 void
  651 constty_clear(void)
  652 {
  653         int c;
  654 
  655         constty = NULL;
  656         if (consbuf == NULL)
  657                 return;
  658         callout_stop(&conscallout);
  659         while ((c = msgbuf_getchar(&consmsgbuf)) != -1)
  660                 cnputc(c);
  661         free(consbuf, M_TTYS);
  662         consbuf = NULL;
  663 }
  664 
  665 /* Times per second to check for pending console tty messages. */
  666 static int constty_wakeups_per_second = 5;
  667 SYSCTL_INT(_kern, OID_AUTO, constty_wakeups_per_second, CTLFLAG_RW,
  668     &constty_wakeups_per_second, 0, "");
  669 
  670 static void
  671 constty_timeout(void *arg)
  672 {
  673         int c;
  674 
  675         while (constty != NULL && (c = msgbuf_getchar(&consmsgbuf)) != -1) {
  676                 if (tputchar(c, constty) < 0)
  677                         constty = NULL;
  678         }
  679         if (constty != NULL) {
  680                 callout_reset(&conscallout, hz / constty_wakeups_per_second,
  681                     constty_timeout, NULL);
  682         } else {
  683                 /* Deallocate the constty buffer memory. */
  684                 constty_clear();
  685         }
  686 }
  687 
  688 static void
  689 cn_drvinit(void *unused)
  690 {
  691 
  692         make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "console");
  693 }
  694 
  695 SYSINIT(cndev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, cn_drvinit, NULL)

Cache object: 86b2aa27555ea088e78194a958dc3cb2


[ 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.