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

Cache object: aeff8e027a7d1a60225ee4cc7ad57db1


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