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

Cache object: e66d5f29fcf7f68e2eff9573a4dc1e9e


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