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

Cache object: c932b6304ad005908213a0ea24536e6f


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