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/i386/i386/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  * $FreeBSD$
   40  */
   41 
   42 #include "opt_devfs.h"
   43 
   44 #include <sys/param.h>
   45 #ifdef DEVFS
   46 #include <sys/devfsext.h>
   47 #endif /*DEVFS*/
   48 #include <sys/systm.h>
   49 #include <sys/conf.h>
   50 #include <sys/kernel.h>
   51 #include <sys/reboot.h>
   52 #include <sys/sysctl.h>
   53 #include <sys/proc.h>
   54 #include <sys/tty.h>
   55 #include <sys/uio.h>
   56 
   57 #include <machine/cpu.h>
   58 #include <machine/cons.h>
   59 
   60 static  d_open_t        cnopen;
   61 static  d_close_t       cnclose;
   62 static  d_read_t        cnread;
   63 static  d_write_t       cnwrite;
   64 static  d_ioctl_t       cnioctl;
   65 static  d_poll_t        cnpoll;
   66 
   67 #define CDEV_MAJOR      0
   68 static  struct cdevsw   cn_cdevsw = {
   69         cnopen,         cnclose,        cnread,         cnwrite,
   70         cnioctl,        nullstop,       nullreset,      nodevtotty,
   71         cnpoll,         nommap,         NULL,           "console",
   72         NULL,           -1,             nodump,         nopsize,
   73         D_TTY,
   74 };
   75 
   76 static dev_t    cn_dev_t;       /* seems to be never really used */
   77 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
   78         &cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
   79 
   80 static int cn_mute;
   81 
   82 int     cons_unavail = 0;       /* XXX:
   83                                  * physical console not available for
   84                                  * input (i.e., it is in graphics mode)
   85                                  */
   86 
   87 static u_char cn_is_open;               /* nonzero if logical console is open */
   88 static int openmode, openflag;          /* how /dev/console was openned */
   89 static u_char cn_phys_is_open;          /* nonzero if physical device is open */
   90 static d_close_t *cn_phys_close;        /* physical device close function */
   91 static d_open_t *cn_phys_open;          /* physical device open function */
   92 static struct consdev *cn_tab;          /* physical console device info */
   93 static struct tty *cn_tp;               /* physical console tty struct */
   94 #ifdef DEVFS
   95 static void *cn_devfs_token;            /* represents the devfs entry */
   96 #endif /* DEVFS */
   97 
   98 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL);
   99 
  100 void
  101 cninit()
  102 {
  103         struct consdev *best_cp, *cp;
  104         struct consdev **list;
  105 
  106         /*
  107          * Find the first console with the highest priority.
  108          */
  109         best_cp = NULL;
  110         list = (struct consdev **)cons_set.ls_items;
  111         while ((cp = *list++) != NULL) {
  112                 if (cp->cn_probe == NULL)
  113                         continue;
  114                 (*cp->cn_probe)(cp);
  115                 if (cp->cn_pri > CN_DEAD &&
  116                     (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
  117                         best_cp = cp;
  118         }
  119 
  120         /*
  121          * Check if we should mute the console (for security reasons perhaps)
  122          * It can be changes dynamically using sysctl kern.consmute
  123          * once we are up and going.
  124          * 
  125          */
  126         cn_mute = ((boothowto & (RB_MUTE
  127                         |RB_SINGLE
  128                         |RB_VERBOSE
  129                         |RB_ASKNAME
  130                         |RB_CONFIG)) == RB_MUTE);
  131         
  132         /*
  133          * If no console, give up.
  134          */
  135         if (best_cp == NULL) {
  136                 cn_tab = best_cp;
  137                 return;
  138         }
  139 
  140         /*
  141          * Initialize console, then attach to it.  This ordering allows
  142          * debugging using the previous console, if any.
  143          * XXX if there was a previous console, then its driver should
  144          * be informed when we forget about it.
  145          */
  146         (*best_cp->cn_init)(best_cp);
  147         cn_tab = best_cp;
  148 }
  149 
  150 void
  151 cninit_finish()
  152 {
  153         struct cdevsw *cdp;
  154 
  155         if ((cn_tab == NULL) || cn_mute)
  156                 return;
  157 
  158         /*
  159          * Hook the open and close functions.
  160          */
  161         cdp = cdevsw[major(cn_tab->cn_dev)];
  162         cn_phys_close = cdp->d_close;
  163         cdp->d_close = cnclose;
  164         cn_phys_open = cdp->d_open;
  165         cdp->d_open = cnopen;
  166         cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
  167         cn_dev_t = cn_tp->t_dev;
  168 }
  169 
  170 static void
  171 cnuninit(void)
  172 {
  173         struct cdevsw *cdp;
  174 
  175         if (cn_tab == NULL)
  176                 return;
  177 
  178         /*
  179          * Unhook the open and close functions.
  180          */
  181         cdp = cdevsw[major(cn_tab->cn_dev)];
  182         cdp->d_close = cn_phys_close;
  183         cn_phys_close = NULL;
  184         cdp->d_open = cn_phys_open;
  185         cn_phys_open = NULL;
  186         cn_tp = NULL;
  187         cn_dev_t = 0;
  188 }
  189 
  190 /*
  191  * User has changed the state of the console muting.
  192  * This may require us to open or close the device in question.
  193  */
  194 static int
  195 sysctl_kern_consmute SYSCTL_HANDLER_ARGS
  196 {
  197         int error;
  198         int ocn_mute;
  199 
  200         ocn_mute = cn_mute;
  201         error = sysctl_handle_int(oidp, &cn_mute, 0, req);
  202         if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
  203                 if(ocn_mute && !cn_mute) {
  204                         /*
  205                          * going from muted to unmuted.. open the physical dev 
  206                          * if the console has been openned
  207                          */
  208                         cninit_finish();
  209                         if(cn_is_open)
  210                                 /* XXX curproc is not what we want really */
  211                                 error = cnopen(cn_dev_t, openflag,
  212                                         openmode, curproc);
  213                         /* if it failed, back it out */
  214                         if ( error != 0) cnuninit();
  215                 } else if (!ocn_mute && cn_mute) {
  216                         /*
  217                          * going from unmuted to muted.. close the physical dev 
  218                          * if it's only open via /dev/console
  219                          */
  220                         if(cn_is_open)
  221                                 error = cnclose(cn_dev_t, openflag,
  222                                         openmode, curproc);
  223                         if ( error == 0) cnuninit();
  224                 }
  225                 if (error != 0) {
  226                         /* 
  227                          * back out the change if there was an error
  228                          */
  229                         cn_mute = ocn_mute;
  230                 }
  231         }
  232         return (error);
  233 }
  234 
  235 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
  236         0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
  237 
  238 static int
  239 cnopen(dev, flag, mode, p)
  240         dev_t dev;
  241         int flag, mode;
  242         struct proc *p;
  243 {
  244         dev_t cndev, physdev;
  245         int retval = 0;
  246 
  247         if (cn_tab == NULL)
  248                 return (0);
  249         cndev = cn_tab->cn_dev;
  250         physdev = (major(dev) == major(cndev) ? dev : cndev);
  251         /*
  252          * If mute is active, then non console opens don't get here
  253          * so we don't need to check for that. They 
  254          * bypass this and go straight to the device.
  255          */
  256         if(!cn_mute)
  257                 retval = (*cn_phys_open)(physdev, flag, mode, p);
  258         if (retval == 0) {
  259                 /* 
  260                  * check if we openned it via /dev/console or 
  261                  * via the physical entry (e.g. /dev/sio0).
  262                  */
  263                 if (dev == cndev)
  264                         cn_phys_is_open = 1;
  265                 else if (physdev == cndev) {
  266                         openmode = mode;
  267                         openflag = flag;
  268                         cn_is_open = 1;
  269                 }
  270         }
  271         return (retval);
  272 }
  273 
  274 static int
  275 cnclose(dev, flag, mode, p)
  276         dev_t dev;
  277         int flag, mode;
  278         struct proc *p;
  279 {
  280         dev_t cndev;
  281 
  282         if (cn_tab == NULL)
  283                 return (0);
  284         cndev = cn_tab->cn_dev;
  285         /*
  286          * act appropriatly depending on whether it's /dev/console
  287          * or the pysical device (e.g. /dev/sio) that's being closed.
  288          * in either case, don't actually close the device unless
  289          * both are closed.
  290          */
  291         if (dev == cndev) {
  292                 /* the physical device is about to be closed */
  293                 cn_phys_is_open = 0;
  294                 if (cn_is_open) {
  295                         if (cn_tp) {
  296                                 /* perform a ttyhalfclose() */
  297                                 /* reset session and proc group */
  298                                 cn_tp->t_pgrp = NULL;
  299                                 cn_tp->t_session = NULL;
  300                         }
  301                         return (0);
  302                 }
  303         } else if (major(dev) != major(cndev)) {
  304                 /* the logical console is about to be closed */
  305                 cn_is_open = 0;
  306                 if (cn_phys_is_open)
  307                         return (0);
  308                 dev = cndev;
  309         }
  310         if(cn_phys_close)
  311                 return ((*cn_phys_close)(dev, flag, mode, p));
  312         return (0);
  313 }
  314 
  315 static int
  316 cnread(dev, uio, flag)
  317         dev_t dev;
  318         struct uio *uio;
  319         int flag;
  320 {
  321         if ((cn_tab == NULL) || cn_mute)
  322                 return (0);
  323         dev = cn_tab->cn_dev;
  324         return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
  325 }
  326 
  327 static int
  328 cnwrite(dev, uio, flag)
  329         dev_t dev;
  330         struct uio *uio;
  331         int flag;
  332 {
  333         if ((cn_tab == NULL) || cn_mute) {
  334                 uio->uio_resid = 0; /* dump the data */
  335                 return (0);
  336         }
  337         if (constty)
  338                 dev = constty->t_dev;
  339         else
  340                 dev = cn_tab->cn_dev;
  341         return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
  342 }
  343 
  344 static int
  345 cnioctl(dev, cmd, data, flag, p)
  346         dev_t dev;
  347         u_long cmd;
  348         caddr_t data;
  349         int flag;
  350         struct proc *p;
  351 {
  352         int error;
  353 
  354         if ((cn_tab == NULL) || cn_mute)
  355                 return (0);
  356         /*
  357          * Superuser can always use this to wrest control of console
  358          * output from the "virtual" console.
  359          */
  360         if (cmd == TIOCCONS && constty) {
  361                 error = suser(p->p_ucred, (u_short *) NULL);
  362                 if (error)
  363                         return (error);
  364                 constty = NULL;
  365                 return (0);
  366         }
  367         dev = cn_tab->cn_dev;
  368         return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
  369 }
  370 
  371 static int
  372 cnpoll(dev, events, p)
  373         dev_t dev;
  374         int events;
  375         struct proc *p;
  376 {
  377         if ((cn_tab == NULL) || cn_mute)
  378                 return (1);
  379 
  380         dev = cn_tab->cn_dev;
  381 
  382         return ((*cdevsw[major(dev)]->d_poll)(dev, events, p));
  383 }
  384 
  385 int
  386 cngetc()
  387 {
  388         int c;
  389         if ((cn_tab == NULL) || cn_mute)
  390                 return (-1);
  391         c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
  392         if (c == '\r') c = '\n'; /* console input is always ICRNL */
  393         return (c);
  394 }
  395 
  396 int
  397 cncheckc()
  398 {
  399         if ((cn_tab == NULL) || cn_mute)
  400                 return (-1);
  401         return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
  402 }
  403 
  404 void
  405 cnputc(c)
  406         register int c;
  407 {
  408         if ((cn_tab == NULL) || cn_mute)
  409                 return;
  410         if (c) {
  411                 if (c == '\n')
  412                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
  413                 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
  414         }
  415 }
  416 
  417 static cn_devsw_installed = 0;
  418 
  419 static void
  420 cn_drvinit(void *unused)
  421 {
  422         dev_t dev;
  423 
  424         if( ! cn_devsw_installed ) {
  425                 dev = makedev(CDEV_MAJOR,0);
  426                 cdevsw_add(&dev,&cn_cdevsw,NULL);
  427                 cn_devsw_installed = 1;
  428 #ifdef DEVFS
  429                 cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR,
  430                                                   UID_ROOT, GID_WHEEL, 0600,
  431                                                   "console");
  432 #endif
  433         }
  434 }
  435 
  436 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
  437 
  438 

Cache object: 6b58203e1c759514891b4d21f5b2bad4


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