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/dev/vt/vt_core.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009, 2013 The FreeBSD Foundation
    5  *
    6  * This software was developed by Ed Schouten under sponsorship from the
    7  * FreeBSD Foundation.
    8  *
    9  * Portions of this software were developed by Oleksandr Rybalko
   10  * under sponsorship from the FreeBSD Foundation.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/consio.h>
   39 #include <sys/devctl.h>
   40 #include <sys/eventhandler.h>
   41 #include <sys/fbio.h>
   42 #include <sys/font.h>
   43 #include <sys/kbio.h>
   44 #include <sys/kdb.h>
   45 #include <sys/kernel.h>
   46 #include <sys/linker.h>
   47 #include <sys/lock.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mutex.h>
   50 #include <sys/power.h>
   51 #include <sys/priv.h>
   52 #include <sys/proc.h>
   53 #include <sys/random.h>
   54 #include <sys/reboot.h>
   55 #include <sys/sbuf.h>
   56 #include <sys/systm.h>
   57 #include <sys/terminal.h>
   58 
   59 #include <dev/kbd/kbdreg.h>
   60 #include <dev/vt/vt.h>
   61 
   62 #if defined(__i386__) || defined(__amd64__)
   63 #include <machine/psl.h>
   64 #include <machine/frame.h>
   65 #endif
   66 
   67 static int vtterm_cngrab_noswitch(struct vt_device *, struct vt_window *);
   68 static int vtterm_cnungrab_noswitch(struct vt_device *, struct vt_window *);
   69 
   70 static tc_bell_t        vtterm_bell;
   71 static tc_cursor_t      vtterm_cursor;
   72 static tc_putchar_t     vtterm_putchar;
   73 static tc_fill_t        vtterm_fill;
   74 static tc_copy_t        vtterm_copy;
   75 static tc_pre_input_t   vtterm_pre_input;
   76 static tc_post_input_t  vtterm_post_input;
   77 static tc_param_t       vtterm_param;
   78 static tc_done_t        vtterm_done;
   79 
   80 static tc_cnprobe_t     vtterm_cnprobe;
   81 static tc_cngetc_t      vtterm_cngetc;
   82 
   83 static tc_cngrab_t      vtterm_cngrab;
   84 static tc_cnungrab_t    vtterm_cnungrab;
   85 
   86 static tc_opened_t      vtterm_opened;
   87 static tc_ioctl_t       vtterm_ioctl;
   88 static tc_mmap_t        vtterm_mmap;
   89 
   90 static const struct terminal_class vt_termclass = {
   91         .tc_bell        = vtterm_bell,
   92         .tc_cursor      = vtterm_cursor,
   93         .tc_putchar     = vtterm_putchar,
   94         .tc_fill        = vtterm_fill,
   95         .tc_copy        = vtterm_copy,
   96         .tc_pre_input   = vtterm_pre_input,
   97         .tc_post_input  = vtterm_post_input,
   98         .tc_param       = vtterm_param,
   99         .tc_done        = vtterm_done,
  100 
  101         .tc_cnprobe     = vtterm_cnprobe,
  102         .tc_cngetc      = vtterm_cngetc,
  103 
  104         .tc_cngrab      = vtterm_cngrab,
  105         .tc_cnungrab    = vtterm_cnungrab,
  106 
  107         .tc_opened      = vtterm_opened,
  108         .tc_ioctl       = vtterm_ioctl,
  109         .tc_mmap        = vtterm_mmap,
  110 };
  111 
  112 /*
  113  * Use a constant timer of 25 Hz to redraw the screen.
  114  *
  115  * XXX: In theory we should only fire up the timer when there is really
  116  * activity. Unfortunately we cannot always start timers. We really
  117  * don't want to process kernel messages synchronously, because it
  118  * really slows down the system.
  119  */
  120 #define VT_TIMERFREQ    25
  121 
  122 /* Bell pitch/duration. */
  123 #define VT_BELLDURATION (SBT_1S / 20)
  124 #define VT_BELLPITCH    (1193182 / 800) /* Approx 1491Hz */
  125 
  126 #define VT_UNIT(vw)     ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
  127                         (vw)->vw_number)
  128 
  129 static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
  130     "vt(9) parameters");
  131 static VT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)");
  132 static VT_SYSCTL_INT(enable_bell, 0, "Enable bell");
  133 static VT_SYSCTL_INT(debug, 0, "vt(9) debug level");
  134 static VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
  135 static VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend");
  136 
  137 /* Allow to disable some keyboard combinations. */
  138 static VT_SYSCTL_INT(kbd_halt, 1, "Enable halt keyboard combination.  "
  139     "See kbdmap(5) to configure.");
  140 static VT_SYSCTL_INT(kbd_poweroff, 1, "Enable Power Off keyboard combination.  "
  141     "See kbdmap(5) to configure.");
  142 static VT_SYSCTL_INT(kbd_reboot, 1, "Enable reboot keyboard combination.  "
  143     "See kbdmap(5) to configure (typically Ctrl-Alt-Delete).");
  144 static VT_SYSCTL_INT(kbd_debug, 1, "Enable key combination to enter debugger.  "
  145     "See kbdmap(5) to configure (typically Ctrl-Alt-Esc).");
  146 static VT_SYSCTL_INT(kbd_panic, 0, "Enable request to panic.  "
  147     "See kbdmap(5) to configure.");
  148 
  149 /* Used internally, not a tunable. */
  150 int vt_draw_logo_cpus;
  151 VT_SYSCTL_INT(splash_cpu, 0, "Show logo CPUs during boot");
  152 VT_SYSCTL_INT(splash_ncpu, 0, "Override number of logos displayed "
  153     "(0 = do not override)");
  154 VT_SYSCTL_INT(splash_cpu_style, 2, "Draw logo style "
  155     "(0 = Alternate beastie, 1 = Beastie, 2 = Orb)");
  156 VT_SYSCTL_INT(splash_cpu_duration, 10, "Hide logos after (seconds)");
  157 
  158 static unsigned int vt_unit = 0;
  159 static MALLOC_DEFINE(M_VT, "vt", "vt device");
  160 struct vt_device *main_vd = &vt_consdev;
  161 
  162 /* Boot logo. */
  163 extern unsigned int vt_logo_width;
  164 extern unsigned int vt_logo_height;
  165 extern unsigned int vt_logo_depth;
  166 extern unsigned char vt_logo_image[];
  167 #ifndef DEV_SPLASH
  168 #define vtterm_draw_cpu_logos(...)      do {} while (0)
  169 const unsigned int vt_logo_sprite_height;
  170 #endif
  171 
  172 /*
  173  * Console font. vt_font_loader will be filled with font data passed
  174  * by loader. If there is no font passed by boot loader, we use built in
  175  * default.
  176  */
  177 extern struct vt_font vt_font_default;
  178 static struct vt_font vt_font_loader;
  179 static struct vt_font *vt_font_assigned = &vt_font_default;
  180 
  181 #ifndef SC_NO_CUTPASTE
  182 extern struct vt_mouse_cursor vt_default_mouse_pointer;
  183 #endif
  184 
  185 static int signal_vt_rel(struct vt_window *);
  186 static int signal_vt_acq(struct vt_window *);
  187 static int finish_vt_rel(struct vt_window *, int, int *);
  188 static int finish_vt_acq(struct vt_window *);
  189 static int vt_window_switch(struct vt_window *);
  190 static int vt_late_window_switch(struct vt_window *);
  191 static int vt_proc_alive(struct vt_window *);
  192 static void vt_resize(struct vt_device *);
  193 static void vt_update_static(void *);
  194 #ifndef SC_NO_CUTPASTE
  195 static void vt_mouse_paste(void);
  196 #endif
  197 static void vt_suspend_handler(void *priv);
  198 static void vt_resume_handler(void *priv);
  199 
  200 SET_DECLARE(vt_drv_set, struct vt_driver);
  201 
  202 #define _VTDEFH MAX(100, PIXEL_HEIGHT(VT_FB_MAX_HEIGHT))
  203 #define _VTDEFW MAX(200, PIXEL_WIDTH(VT_FB_MAX_WIDTH))
  204 
  205 static struct terminal  vt_consterm;
  206 static struct vt_window vt_conswindow;
  207 #ifndef SC_NO_CONSDRAWN
  208 static term_char_t vt_consdrawn[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
  209 static term_color_t vt_consdrawnfg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
  210 static term_color_t vt_consdrawnbg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)];
  211 #endif
  212 struct vt_device        vt_consdev = {
  213         .vd_driver = NULL,
  214         .vd_softc = NULL,
  215         .vd_prev_driver = NULL,
  216         .vd_prev_softc = NULL,
  217         .vd_flags = VDF_INVALID,
  218         .vd_windows = { [VT_CONSWINDOW] =  &vt_conswindow, },
  219         .vd_curwindow = &vt_conswindow,
  220         .vd_kbstate = 0,
  221 
  222 #ifndef SC_NO_CUTPASTE
  223         .vd_pastebuf = {
  224                 .vpb_buf = NULL,
  225                 .vpb_bufsz = 0,
  226                 .vpb_len = 0
  227         },
  228         .vd_mcursor = &vt_default_mouse_pointer,
  229         .vd_mcursor_fg = TC_WHITE,
  230         .vd_mcursor_bg = TC_BLACK,
  231 #endif
  232 
  233 #ifndef SC_NO_CONSDRAWN
  234         .vd_drawn = vt_consdrawn,
  235         .vd_drawnfg = vt_consdrawnfg,
  236         .vd_drawnbg = vt_consdrawnbg,
  237 #endif
  238 };
  239 static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)];
  240 static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE];
  241 static struct vt_window vt_conswindow = {
  242         .vw_number = VT_CONSWINDOW,
  243         .vw_flags = VWF_CONSOLE,
  244         .vw_buf = {
  245                 .vb_buffer = &vt_constextbuf[0],
  246                 .vb_rows = &vt_constextbufrows[0],
  247                 .vb_history_size = VBF_DEFAULT_HISTORY_SIZE,
  248                 .vb_curroffset = 0,
  249                 .vb_roffset = 0,
  250                 .vb_flags = VBF_STATIC,
  251                 .vb_mark_start = {.tp_row = 0, .tp_col = 0,},
  252                 .vb_mark_end = {.tp_row = 0, .tp_col = 0,},
  253                 .vb_scr_size = {
  254                         .tp_row = _VTDEFH,
  255                         .tp_col = _VTDEFW,
  256                 },
  257         },
  258         .vw_device = &vt_consdev,
  259         .vw_terminal = &vt_consterm,
  260         .vw_kbdmode = K_XLATE,
  261         .vw_grabbed = 0,
  262         .vw_bell_pitch = VT_BELLPITCH,
  263         .vw_bell_duration = VT_BELLDURATION,
  264 };
  265 
  266 /* Add to set of consoles. */
  267 TERMINAL_DECLARE_EARLY(vt_consterm, vt_termclass, &vt_conswindow);
  268 
  269 /*
  270  * Right after kmem is done to allow early drivers to use locking and allocate
  271  * memory.
  272  */
  273 SYSINIT(vt_update_static, SI_SUB_KMEM, SI_ORDER_ANY, vt_update_static,
  274     &vt_consdev);
  275 /* Delay until all devices attached, to not waste time. */
  276 SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade,
  277     &vt_consdev);
  278 
  279 /* Initialize locks/mem depended members. */
  280 static void
  281 vt_update_static(void *dummy)
  282 {
  283 
  284         if (!vty_enabled(VTY_VT))
  285                 return;
  286         if (main_vd->vd_driver != NULL)
  287                 printf("VT(%s): %s %ux%u\n", main_vd->vd_driver->vd_name,
  288                     (main_vd->vd_flags & VDF_TEXTMODE) ? "text" : "resolution",
  289                     main_vd->vd_width, main_vd->vd_height);
  290         else
  291                 printf("VT: init without driver.\n");
  292 
  293         mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF);
  294         cv_init(&main_vd->vd_winswitch, "vtwswt");
  295 }
  296 
  297 static void
  298 vt_schedule_flush(struct vt_device *vd, int ms)
  299 {
  300 
  301         if (ms <= 0)
  302                 /* Default to initial value. */
  303                 ms = 1000 / VT_TIMERFREQ;
  304 
  305         callout_schedule(&vd->vd_timer, hz / (1000 / ms));
  306 }
  307 
  308 void
  309 vt_resume_flush_timer(struct vt_window *vw, int ms)
  310 {
  311         struct vt_device *vd = vw->vw_device;
  312 
  313         if (vd->vd_curwindow != vw)
  314                 return;
  315 
  316         if (!(vd->vd_flags & VDF_ASYNC) ||
  317             !atomic_cmpset_int(&vd->vd_timer_armed, 0, 1))
  318                 return;
  319 
  320         vt_schedule_flush(vd, ms);
  321 }
  322 
  323 static void
  324 vt_suspend_flush_timer(struct vt_device *vd)
  325 {
  326         /*
  327          * As long as this function is called locked, callout_stop()
  328          * has the same effect like callout_drain() with regard to
  329          * preventing the callback function from executing.
  330          */
  331         VT_LOCK_ASSERT(vd, MA_OWNED);
  332 
  333         if (!(vd->vd_flags & VDF_ASYNC) ||
  334             !atomic_cmpset_int(&vd->vd_timer_armed, 1, 0))
  335                 return;
  336 
  337         callout_stop(&vd->vd_timer);
  338 }
  339 
  340 static void
  341 vt_switch_timer(void *arg, int pending)
  342 {
  343 
  344         (void)vt_late_window_switch((struct vt_window *)arg);
  345 }
  346 
  347 static int
  348 vt_save_kbd_mode(struct vt_window *vw, keyboard_t *kbd)
  349 {
  350         int mode, ret;
  351 
  352         mode = 0;
  353         ret = kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode);
  354         if (ret == ENOIOCTL)
  355                 ret = ENODEV;
  356         if (ret != 0)
  357                 return (ret);
  358 
  359         vw->vw_kbdmode = mode;
  360 
  361         return (0);
  362 }
  363 
  364 static int
  365 vt_update_kbd_mode(struct vt_window *vw, keyboard_t *kbd)
  366 {
  367         int ret;
  368 
  369         ret = kbdd_ioctl(kbd, KDSKBMODE, (caddr_t)&vw->vw_kbdmode);
  370         if (ret == ENOIOCTL)
  371                 ret = ENODEV;
  372 
  373         return (ret);
  374 }
  375 
  376 static int
  377 vt_save_kbd_state(struct vt_window *vw, keyboard_t *kbd)
  378 {
  379         int state, ret;
  380 
  381         state = 0;
  382         ret = kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
  383         if (ret == ENOIOCTL)
  384                 ret = ENODEV;
  385         if (ret != 0)
  386                 return (ret);
  387 
  388         vw->vw_kbdstate &= ~LOCK_MASK;
  389         vw->vw_kbdstate |= state & LOCK_MASK;
  390 
  391         return (0);
  392 }
  393 
  394 static int
  395 vt_update_kbd_state(struct vt_window *vw, keyboard_t *kbd)
  396 {
  397         int state, ret;
  398 
  399         state = vw->vw_kbdstate & LOCK_MASK;
  400         ret = kbdd_ioctl(kbd, KDSKBSTATE, (caddr_t)&state);
  401         if (ret == ENOIOCTL)
  402                 ret = ENODEV;
  403 
  404         return (ret);
  405 }
  406 
  407 static int
  408 vt_save_kbd_leds(struct vt_window *vw, keyboard_t *kbd)
  409 {
  410         int leds, ret;
  411 
  412         leds = 0;
  413         ret = kbdd_ioctl(kbd, KDGETLED, (caddr_t)&leds);
  414         if (ret == ENOIOCTL)
  415                 ret = ENODEV;
  416         if (ret != 0)
  417                 return (ret);
  418 
  419         vw->vw_kbdstate &= ~LED_MASK;
  420         vw->vw_kbdstate |= leds & LED_MASK;
  421 
  422         return (0);
  423 }
  424 
  425 static int
  426 vt_update_kbd_leds(struct vt_window *vw, keyboard_t *kbd)
  427 {
  428         int leds, ret;
  429 
  430         leds = vw->vw_kbdstate & LED_MASK;
  431         ret = kbdd_ioctl(kbd, KDSETLED, (caddr_t)&leds);
  432         if (ret == ENOIOCTL)
  433                 ret = ENODEV;
  434 
  435         return (ret);
  436 }
  437 
  438 static int
  439 vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
  440 {
  441 
  442         DPRINTF(40, "%s\n", __func__);
  443         curvw->vw_switch_to = vw;
  444         /* Set timer to allow switch in case when process hang. */
  445         taskqueue_enqueue_timeout(taskqueue_thread, &vw->vw_timeout_task_dead, hz * vt_deadtimer);
  446         /* Notify process about vt switch attempt. */
  447         DPRINTF(30, "%s: Notify process.\n", __func__);
  448         signal_vt_rel(curvw);
  449 
  450         return (0);
  451 }
  452 
  453 static int
  454 vt_window_postswitch(struct vt_window *vw)
  455 {
  456 
  457         signal_vt_acq(vw);
  458         return (0);
  459 }
  460 
  461 /* vt_late_window_switch will do VT switching for regular case. */
  462 static int
  463 vt_late_window_switch(struct vt_window *vw)
  464 {
  465         struct vt_window *curvw;
  466         int ret;
  467 
  468         taskqueue_cancel_timeout(taskqueue_thread, &vw->vw_timeout_task_dead, NULL);
  469 
  470         ret = vt_window_switch(vw);
  471         if (ret != 0) {
  472                 /*
  473                  * If the switch hasn't happened, then return the VT
  474                  * to the current owner, if any.
  475                  */
  476                 curvw = vw->vw_device->vd_curwindow;
  477                 if (curvw->vw_smode.mode == VT_PROCESS)
  478                         (void)vt_window_postswitch(curvw);
  479                 return (ret);
  480         }
  481 
  482         /* Notify owner process about terminal availability. */
  483         if (vw->vw_smode.mode == VT_PROCESS) {
  484                 ret = vt_window_postswitch(vw);
  485         }
  486         return (ret);
  487 }
  488 
  489 /* Switch window. */
  490 static int
  491 vt_proc_window_switch(struct vt_window *vw)
  492 {
  493         struct vt_window *curvw;
  494         struct vt_device *vd;
  495         int ret;
  496 
  497         /* Prevent switching to NULL */
  498         if (vw == NULL) {
  499                 DPRINTF(30, "%s: Cannot switch: vw is NULL.", __func__);
  500                 return (EINVAL);
  501         }
  502         vd = vw->vw_device;
  503         curvw = vd->vd_curwindow;
  504 
  505         /* Check if virtual terminal is locked */
  506         if (curvw->vw_flags & VWF_VTYLOCK)
  507                 return (EBUSY);
  508 
  509         /* Check if switch already in progress */
  510         if (curvw->vw_flags & VWF_SWWAIT_REL) {
  511                 /* Check if switching to same window */
  512                 if (curvw->vw_switch_to == vw) {
  513                         DPRINTF(30, "%s: Switch in progress to same vw.", __func__);
  514                         return (0);     /* success */
  515                 }
  516                 DPRINTF(30, "%s: Switch in progress to different vw.", __func__);
  517                 return (EBUSY);
  518         }
  519 
  520         /* Avoid switching to already selected window */
  521         if (vw == curvw) {
  522                 DPRINTF(30, "%s: Cannot switch: vw == curvw.", __func__);
  523                 return (0);     /* success */
  524         }
  525 
  526         /*
  527          * Early check for an attempt to switch to a non-functional VT.
  528          * The same check is done in vt_window_switch(), but it's better
  529          * to fail as early as possible to avoid needless pre-switch
  530          * actions.
  531          */
  532         VT_LOCK(vd);
  533         if ((vw->vw_flags & (VWF_OPENED|VWF_CONSOLE)) == 0) {
  534                 VT_UNLOCK(vd);
  535                 return (EINVAL);
  536         }
  537         VT_UNLOCK(vd);
  538 
  539         /* Ask current process permission to switch away. */
  540         if (curvw->vw_smode.mode == VT_PROCESS) {
  541                 DPRINTF(30, "%s: VT_PROCESS ", __func__);
  542                 if (vt_proc_alive(curvw) == FALSE) {
  543                         DPRINTF(30, "Dead. Cleaning.");
  544                         /* Dead */
  545                 } else {
  546                         DPRINTF(30, "%s: Signaling process.\n", __func__);
  547                         /* Alive, try to ask him. */
  548                         ret = vt_window_preswitch(vw, curvw);
  549                         /* Wait for process answer or timeout. */
  550                         return (ret);
  551                 }
  552                 DPRINTF(30, "\n");
  553         }
  554 
  555         ret = vt_late_window_switch(vw);
  556         return (ret);
  557 }
  558 
  559 /* Switch window ignoring process locking. */
  560 static int
  561 vt_window_switch(struct vt_window *vw)
  562 {
  563         struct vt_device *vd = vw->vw_device;
  564         struct vt_window *curvw = vd->vd_curwindow;
  565         keyboard_t *kbd;
  566 
  567         if (kdb_active) {
  568                 /*
  569                  * When grabbing the console for the debugger, avoid
  570                  * locks as that can result in deadlock.  While this
  571                  * could use try locks, that wouldn't really make a
  572                  * difference as there are sufficient barriers in
  573                  * debugger entry/exit to be equivalent to
  574                  * successfully try-locking here.
  575                  */
  576                 if (curvw == vw)
  577                         return (0);
  578                 if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE)))
  579                         return (EINVAL);
  580 
  581                 vd->vd_curwindow = vw;
  582                 vd->vd_flags |= VDF_INVALID;
  583                 if (vd->vd_driver->vd_postswitch)
  584                         vd->vd_driver->vd_postswitch(vd);
  585                 return (0);
  586         }
  587 
  588         VT_LOCK(vd);
  589         if (curvw == vw) {
  590                 /*
  591                  * Nothing to do, except ensure the driver has the opportunity to
  592                  * switch to console mode when panicking, making sure the panic
  593                  * is readable (even when a GUI was using ttyv0).
  594                  */
  595                 if ((kdb_active || KERNEL_PANICKED()) &&
  596                     vd->vd_driver->vd_postswitch)
  597                         vd->vd_driver->vd_postswitch(vd);
  598                 VT_UNLOCK(vd);
  599                 return (0);
  600         }
  601         if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
  602                 VT_UNLOCK(vd);
  603                 return (EINVAL);
  604         }
  605 
  606         vt_suspend_flush_timer(vd);
  607 
  608         vd->vd_curwindow = vw;
  609         vd->vd_flags |= VDF_INVALID;
  610         cv_broadcast(&vd->vd_winswitch);
  611         VT_UNLOCK(vd);
  612 
  613         if (vd->vd_driver->vd_postswitch)
  614                 vd->vd_driver->vd_postswitch(vd);
  615 
  616         vt_resume_flush_timer(vw, 0);
  617 
  618         /* Restore per-window keyboard mode. */
  619         mtx_lock(&Giant);
  620         if ((kbd = vd->vd_keyboard) != NULL) {
  621                 if (curvw->vw_kbdmode == K_XLATE)
  622                         vt_save_kbd_state(curvw, kbd);
  623 
  624                 vt_update_kbd_mode(vw, kbd);
  625                 vt_update_kbd_state(vw, kbd);
  626         }
  627         mtx_unlock(&Giant);
  628         DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
  629 
  630         return (0);
  631 }
  632 
  633 void
  634 vt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size)
  635 {
  636 
  637         size->tp_row = vd->vd_height;
  638         if (vt_draw_logo_cpus)
  639                 size->tp_row -= vt_logo_sprite_height;
  640         size->tp_col = vd->vd_width;
  641         if (vf != NULL) {
  642                 size->tp_row = MIN(size->tp_row / vf->vf_height,
  643                     PIXEL_HEIGHT(VT_FB_MAX_HEIGHT));
  644                 size->tp_col = MIN(size->tp_col / vf->vf_width,
  645                     PIXEL_WIDTH(VT_FB_MAX_WIDTH));
  646         }
  647 }
  648 
  649 static inline void
  650 vt_termrect(struct vt_device *vd, struct vt_font *vf, term_rect_t *rect)
  651 {
  652 
  653         rect->tr_begin.tp_row = rect->tr_begin.tp_col = 0;
  654         if (vt_draw_logo_cpus)
  655                 rect->tr_begin.tp_row = vt_logo_sprite_height;
  656 
  657         rect->tr_end.tp_row = vd->vd_height;
  658         rect->tr_end.tp_col = vd->vd_width;
  659 
  660         if (vf != NULL) {
  661                 rect->tr_begin.tp_row =
  662                     howmany(rect->tr_begin.tp_row, vf->vf_height);
  663 
  664                 rect->tr_end.tp_row = MIN(rect->tr_end.tp_row / vf->vf_height,
  665                     PIXEL_HEIGHT(VT_FB_MAX_HEIGHT));
  666                 rect->tr_end.tp_col = MIN(rect->tr_end.tp_col / vf->vf_width,
  667                     PIXEL_WIDTH(VT_FB_MAX_WIDTH));
  668         }
  669 }
  670 
  671 void
  672 vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size)
  673 {
  674 
  675         size->ws_ypixel = vd->vd_height;
  676         if (vt_draw_logo_cpus)
  677                 size->ws_ypixel -= vt_logo_sprite_height;
  678         size->ws_row = size->ws_ypixel;
  679         size->ws_col = size->ws_xpixel = vd->vd_width;
  680         if (vf != NULL) {
  681                 size->ws_row = MIN(size->ws_row / vf->vf_height,
  682                     PIXEL_HEIGHT(VT_FB_MAX_HEIGHT));
  683                 size->ws_col = MIN(size->ws_col / vf->vf_width,
  684                     PIXEL_WIDTH(VT_FB_MAX_WIDTH));
  685         }
  686 }
  687 
  688 void
  689 vt_compute_drawable_area(struct vt_window *vw)
  690 {
  691         struct vt_device *vd;
  692         struct vt_font *vf;
  693         vt_axis_t height;
  694 
  695         vd = vw->vw_device;
  696 
  697         if (vw->vw_font == NULL) {
  698                 vw->vw_draw_area.tr_begin.tp_col = 0;
  699                 vw->vw_draw_area.tr_begin.tp_row = 0;
  700                 if (vt_draw_logo_cpus)
  701                         vw->vw_draw_area.tr_begin.tp_row = vt_logo_sprite_height;
  702                 vw->vw_draw_area.tr_end.tp_col = vd->vd_width;
  703                 vw->vw_draw_area.tr_end.tp_row = vd->vd_height;
  704                 return;
  705         }
  706 
  707         vf = vw->vw_font;
  708 
  709         /*
  710          * Compute the drawable area, so that the text is centered on
  711          * the screen.
  712          */
  713 
  714         height = vd->vd_height;
  715         if (vt_draw_logo_cpus)
  716                 height -= vt_logo_sprite_height;
  717         vw->vw_draw_area.tr_begin.tp_col = (vd->vd_width % vf->vf_width) / 2;
  718         vw->vw_draw_area.tr_begin.tp_row = (height % vf->vf_height) / 2;
  719         if (vt_draw_logo_cpus)
  720                 vw->vw_draw_area.tr_begin.tp_row += vt_logo_sprite_height;
  721         vw->vw_draw_area.tr_end.tp_col = vw->vw_draw_area.tr_begin.tp_col +
  722             rounddown(vd->vd_width, vf->vf_width);
  723         vw->vw_draw_area.tr_end.tp_row = vw->vw_draw_area.tr_begin.tp_row +
  724             rounddown(height, vf->vf_height);
  725 }
  726 
  727 static void
  728 vt_scroll(struct vt_window *vw, int offset, int whence)
  729 {
  730         int diff;
  731         term_pos_t size;
  732 
  733         if ((vw->vw_flags & VWF_SCROLL) == 0)
  734                 return;
  735 
  736         vt_termsize(vw->vw_device, vw->vw_font, &size);
  737 
  738         diff = vthistory_seek(&vw->vw_buf, offset, whence);
  739         if (diff)
  740                 vw->vw_device->vd_flags |= VDF_INVALID;
  741         vt_resume_flush_timer(vw, 0);
  742 }
  743 
  744 static int
  745 vt_machine_kbdevent(struct vt_device *vd, int c)
  746 {
  747 
  748         switch (c) {
  749         case SPCLKEY | DBG: /* kbdmap(5) keyword `debug`. */
  750                 if (vt_kbd_debug) {
  751                         kdb_enter(KDB_WHY_BREAK, "manual escape to debugger");
  752 #if VT_ALT_TO_ESC_HACK
  753                         /*
  754                          * There's an unfortunate conflict between SPCLKEY|DBG
  755                          * and VT_ALT_TO_ESC_HACK.  Just assume they didn't mean
  756                          * it if we got to here.
  757                          */
  758                         vd->vd_kbstate &= ~ALKED;
  759 #endif
  760                 }
  761                 return (1);
  762         case SPCLKEY | HALT: /* kbdmap(5) keyword `halt`. */
  763                 if (vt_kbd_halt)
  764                         shutdown_nice(RB_HALT);
  765                 return (1);
  766         case SPCLKEY | PASTE: /* kbdmap(5) keyword `paste`. */
  767 #ifndef SC_NO_CUTPASTE
  768                 /* Insert text from cut-paste buffer. */
  769                 vt_mouse_paste();
  770 #endif
  771                 break;
  772         case SPCLKEY | PDWN: /* kbdmap(5) keyword `pdwn`. */
  773                 if (vt_kbd_poweroff)
  774                         shutdown_nice(RB_HALT|RB_POWEROFF);
  775                 return (1);
  776         case SPCLKEY | PNC: /* kbdmap(5) keyword `panic`. */
  777                 /*
  778                  * Request to immediate panic if sysctl
  779                  * kern.vt.enable_panic_key allow it.
  780                  */
  781                 if (vt_kbd_panic)
  782                         panic("Forced by the panic key");
  783                 return (1);
  784         case SPCLKEY | RBT: /* kbdmap(5) keyword `boot`. */
  785                 if (vt_kbd_reboot)
  786                         shutdown_nice(RB_AUTOBOOT);
  787                 return (1);
  788         case SPCLKEY | SPSC: /* kbdmap(5) keyword `spsc`. */
  789                 /* Force activatation/deactivation of the screen saver. */
  790                 /* TODO */
  791                 return (1);
  792         case SPCLKEY | STBY: /* XXX Not present in kbdcontrol parser. */
  793                 /* Put machine into Stand-By mode. */
  794                 power_pm_suspend(POWER_SLEEP_STATE_STANDBY);
  795                 return (1);
  796         case SPCLKEY | SUSP: /* kbdmap(5) keyword `susp`. */
  797                 /* Suspend machine. */
  798                 power_pm_suspend(POWER_SLEEP_STATE_SUSPEND);
  799                 return (1);
  800         }
  801 
  802         return (0);
  803 }
  804 
  805 static void
  806 vt_scrollmode_kbdevent(struct vt_window *vw, int c, int console)
  807 {
  808         struct vt_device *vd;
  809         term_pos_t size;
  810 
  811         vd = vw->vw_device;
  812         /* Only special keys handled in ScrollLock mode */
  813         if ((c & SPCLKEY) == 0)
  814                 return;
  815 
  816         c &= ~SPCLKEY;
  817 
  818         if (console == 0) {
  819                 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
  820                         vw = vd->vd_windows[c - F_SCR];
  821                         vt_proc_window_switch(vw);
  822                         return;
  823                 }
  824                 VT_LOCK(vd);
  825         }
  826 
  827         switch (c) {
  828         case SLK: {
  829                 /* Turn scrolling off. */
  830                 vt_scroll(vw, 0, VHS_END);
  831                 VTBUF_SLCK_DISABLE(&vw->vw_buf);
  832                 vw->vw_flags &= ~VWF_SCROLL;
  833                 break;
  834         }
  835         case FKEY | F(49): /* Home key. */
  836                 vt_scroll(vw, 0, VHS_SET);
  837                 break;
  838         case FKEY | F(50): /* Arrow up. */
  839                 vt_scroll(vw, -1, VHS_CUR);
  840                 break;
  841         case FKEY | F(51): /* Page up. */
  842                 vt_termsize(vd, vw->vw_font, &size);
  843                 vt_scroll(vw, -size.tp_row, VHS_CUR);
  844                 break;
  845         case FKEY | F(57): /* End key. */
  846                 vt_scroll(vw, 0, VHS_END);
  847                 break;
  848         case FKEY | F(58): /* Arrow down. */
  849                 vt_scroll(vw, 1, VHS_CUR);
  850                 break;
  851         case FKEY | F(59): /* Page down. */
  852                 vt_termsize(vd, vw->vw_font, &size);
  853                 vt_scroll(vw, size.tp_row, VHS_CUR);
  854                 break;
  855         }
  856 
  857         if (console == 0)
  858                 VT_UNLOCK(vd);
  859 }
  860 
  861 static int
  862 vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
  863 {
  864         struct vt_window *vw = vd->vd_curwindow;
  865 
  866         random_harvest_queue(&c, sizeof(c), RANDOM_KEYBOARD);
  867 #if VT_ALT_TO_ESC_HACK
  868         if (c & RELKEY) {
  869                 switch (c & ~RELKEY) {
  870                 case (SPCLKEY | RALT):
  871                         if (vt_enable_altgr != 0)
  872                                 break;
  873                 case (SPCLKEY | LALT):
  874                         vd->vd_kbstate &= ~ALKED;
  875                 }
  876                 /* Other keys ignored for RELKEY event. */
  877                 return (0);
  878         } else {
  879                 switch (c & ~RELKEY) {
  880                 case (SPCLKEY | RALT):
  881                         if (vt_enable_altgr != 0)
  882                                 break;
  883                 case (SPCLKEY | LALT):
  884                         vd->vd_kbstate |= ALKED;
  885                 }
  886         }
  887 #else
  888         if (c & RELKEY)
  889                 /* Other keys ignored for RELKEY event. */
  890                 return (0);
  891 #endif
  892 
  893         if (vt_machine_kbdevent(vd, c))
  894                 return (0);
  895 
  896         if (vw->vw_flags & VWF_SCROLL) {
  897                 vt_scrollmode_kbdevent(vw, c, 0/* Not a console */);
  898                 /* Scroll mode keys handled, nothing to do more. */
  899                 return (0);
  900         }
  901 
  902         if (c & SPCLKEY) {
  903                 c &= ~SPCLKEY;
  904 
  905                 if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
  906                         vw = vd->vd_windows[c - F_SCR];
  907                         vt_proc_window_switch(vw);
  908                         return (0);
  909                 }
  910 
  911                 switch (c) {
  912                 case NEXT:
  913                         /* Switch to next VT. */
  914                         c = (vw->vw_number + 1) % VT_MAXWINDOWS;
  915                         vw = vd->vd_windows[c];
  916                         vt_proc_window_switch(vw);
  917                         return (0);
  918                 case PREV:
  919                         /* Switch to previous VT. */
  920                         c = (vw->vw_number + VT_MAXWINDOWS - 1) % VT_MAXWINDOWS;
  921                         vw = vd->vd_windows[c];
  922                         vt_proc_window_switch(vw);
  923                         return (0);
  924                 case SLK: {
  925                         vt_save_kbd_state(vw, kbd);
  926                         VT_LOCK(vd);
  927                         if (vw->vw_kbdstate & SLKED) {
  928                                 /* Turn scrolling on. */
  929                                 vw->vw_flags |= VWF_SCROLL;
  930                                 VTBUF_SLCK_ENABLE(&vw->vw_buf);
  931                         } else {
  932                                 /* Turn scrolling off. */
  933                                 vw->vw_flags &= ~VWF_SCROLL;
  934                                 VTBUF_SLCK_DISABLE(&vw->vw_buf);
  935                                 vt_scroll(vw, 0, VHS_END);
  936                         }
  937                         VT_UNLOCK(vd);
  938                         break;
  939                 }
  940                 case FKEY | F(1):  case FKEY | F(2):  case FKEY | F(3):
  941                 case FKEY | F(4):  case FKEY | F(5):  case FKEY | F(6):
  942                 case FKEY | F(7):  case FKEY | F(8):  case FKEY | F(9):
  943                 case FKEY | F(10): case FKEY | F(11): case FKEY | F(12):
  944                         /* F1 through F12 keys. */
  945                         terminal_input_special(vw->vw_terminal,
  946                             TKEY_F1 + c - (FKEY | F(1)));
  947                         break;
  948                 case FKEY | F(49): /* Home key. */
  949                         terminal_input_special(vw->vw_terminal, TKEY_HOME);
  950                         break;
  951                 case FKEY | F(50): /* Arrow up. */
  952                         terminal_input_special(vw->vw_terminal, TKEY_UP);
  953                         break;
  954                 case FKEY | F(51): /* Page up. */
  955                         terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP);
  956                         break;
  957                 case FKEY | F(53): /* Arrow left. */
  958                         terminal_input_special(vw->vw_terminal, TKEY_LEFT);
  959                         break;
  960                 case FKEY | F(55): /* Arrow right. */
  961                         terminal_input_special(vw->vw_terminal, TKEY_RIGHT);
  962                         break;
  963                 case FKEY | F(57): /* End key. */
  964                         terminal_input_special(vw->vw_terminal, TKEY_END);
  965                         break;
  966                 case FKEY | F(58): /* Arrow down. */
  967                         terminal_input_special(vw->vw_terminal, TKEY_DOWN);
  968                         break;
  969                 case FKEY | F(59): /* Page down. */
  970                         terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN);
  971                         break;
  972                 case FKEY | F(60): /* Insert key. */
  973                         terminal_input_special(vw->vw_terminal, TKEY_INSERT);
  974                         break;
  975                 case FKEY | F(61): /* Delete key. */
  976                         terminal_input_special(vw->vw_terminal, TKEY_DELETE);
  977                         break;
  978                 }
  979         } else if (KEYFLAGS(c) == 0) {
  980                 /* Don't do UTF-8 conversion when doing raw mode. */
  981                 if (vw->vw_kbdmode == K_XLATE) {
  982 #if VT_ALT_TO_ESC_HACK
  983                         if (vd->vd_kbstate & ALKED) {
  984                                 /*
  985                                  * Prepend ESC sequence if one of ALT keys down.
  986                                  */
  987                                 terminal_input_char(vw->vw_terminal, 0x1b);
  988                         }
  989 #endif
  990 #if defined(KDB)
  991                         kdb_alt_break(c, &vd->vd_altbrk);
  992 #endif
  993                         terminal_input_char(vw->vw_terminal, KEYCHAR(c));
  994                 } else
  995                         terminal_input_raw(vw->vw_terminal, c);
  996         }
  997         return (0);
  998 }
  999 
 1000 static int
 1001 vt_kbdevent(keyboard_t *kbd, int event, void *arg)
 1002 {
 1003         struct vt_device *vd = arg;
 1004         int c;
 1005 
 1006         switch (event) {
 1007         case KBDIO_KEYINPUT:
 1008                 break;
 1009         case KBDIO_UNLOADING:
 1010                 mtx_lock(&Giant);
 1011                 vd->vd_keyboard = NULL;
 1012                 kbd_release(kbd, (void *)vd);
 1013                 mtx_unlock(&Giant);
 1014                 return (0);
 1015         default:
 1016                 return (EINVAL);
 1017         }
 1018 
 1019         while ((c = kbdd_read_char(kbd, 0)) != NOKEY)
 1020                 vt_processkey(kbd, vd, c);
 1021 
 1022         return (0);
 1023 }
 1024 
 1025 static int
 1026 vt_allocate_keyboard(struct vt_device *vd)
 1027 {
 1028         int              grabbed, i, idx0, idx;
 1029         keyboard_t      *k0, *k;
 1030         keyboard_info_t  ki;
 1031 
 1032         /*
 1033          * If vt_upgrade() happens while the console is grabbed, we are
 1034          * potentially going to switch keyboard devices while the keyboard is in
 1035          * use. Unwind the grabbing of the current keyboard first, then we will
 1036          * re-grab the new keyboard below, before we return.
 1037          */
 1038         if (vd->vd_curwindow == &vt_conswindow) {
 1039                 grabbed = vd->vd_curwindow->vw_grabbed;
 1040                 for (i = 0; i < grabbed; ++i)
 1041                         vtterm_cnungrab_noswitch(vd, vd->vd_curwindow);
 1042         }
 1043 
 1044         idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd);
 1045         if (idx0 >= 0) {
 1046                 DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
 1047                 k0 = kbd_get_keyboard(idx0);
 1048 
 1049                 for (idx = kbd_find_keyboard2("*", -1, 0);
 1050                      idx != -1;
 1051                      idx = kbd_find_keyboard2("*", -1, idx + 1)) {
 1052                         k = kbd_get_keyboard(idx);
 1053 
 1054                         if (idx == idx0 || KBD_IS_BUSY(k))
 1055                                 continue;
 1056 
 1057                         bzero(&ki, sizeof(ki));
 1058                         strncpy(ki.kb_name, k->kb_name, sizeof(ki.kb_name));
 1059                         ki.kb_name[sizeof(ki.kb_name) - 1] = '\0';
 1060                         ki.kb_unit = k->kb_unit;
 1061 
 1062                         kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
 1063                 }
 1064         } else {
 1065                 DPRINTF(20, "%s: no kbdmux allocated\n", __func__);
 1066                 idx0 = kbd_allocate("*", -1, vd, vt_kbdevent, vd);
 1067                 if (idx0 < 0) {
 1068                         DPRINTF(10, "%s: No keyboard found.\n", __func__);
 1069                         return (-1);
 1070                 }
 1071                 k0 = kbd_get_keyboard(idx0);
 1072         }
 1073         vd->vd_keyboard = k0;
 1074         DPRINTF(20, "%s: vd_keyboard = %d\n", __func__,
 1075             vd->vd_keyboard->kb_index);
 1076 
 1077         if (vd->vd_curwindow == &vt_conswindow) {
 1078                 for (i = 0; i < grabbed; ++i)
 1079                         vtterm_cngrab_noswitch(vd, vd->vd_curwindow);
 1080         }
 1081 
 1082         return (idx0);
 1083 }
 1084 
 1085 #define DEVCTL_LEN 64
 1086 static void
 1087 vtterm_devctl(bool enabled, bool hushed, int hz, sbintime_t duration)
 1088 {
 1089         struct sbuf sb;
 1090         char *buf;
 1091 
 1092         buf = malloc(DEVCTL_LEN, M_VT, M_NOWAIT);
 1093         if (buf == NULL)
 1094                 return;
 1095         sbuf_new(&sb, buf, DEVCTL_LEN, SBUF_FIXEDLEN);
 1096         sbuf_printf(&sb, "enabled=%s hushed=%s hz=%d duration_ms=%d",
 1097             enabled ? "true" : "false", hushed ? "true" : "false",
 1098             hz, (int)(duration / SBT_1MS));
 1099         sbuf_finish(&sb);
 1100         if (sbuf_error(&sb) == 0)
 1101                 devctl_notify("VT", "BELL", "RING", sbuf_data(&sb));
 1102         sbuf_delete(&sb);
 1103         free(buf, M_VT);
 1104 }
 1105 
 1106 static void
 1107 vtterm_bell(struct terminal *tm)
 1108 {
 1109         struct vt_window *vw = tm->tm_softc;
 1110         struct vt_device *vd = vw->vw_device;
 1111 
 1112         vtterm_devctl(vt_enable_bell, vd->vd_flags & VDF_QUIET_BELL,
 1113             vw->vw_bell_pitch, vw->vw_bell_duration);
 1114 
 1115         if (!vt_enable_bell)
 1116                 return;
 1117 
 1118         if (vd->vd_flags & VDF_QUIET_BELL)
 1119                 return;
 1120 
 1121         if (vw->vw_bell_pitch == 0 ||
 1122             vw->vw_bell_duration == 0)
 1123                 return;
 1124 
 1125         sysbeep(vw->vw_bell_pitch, vw->vw_bell_duration);
 1126 }
 1127 
 1128 static void
 1129 vtterm_beep(struct terminal *tm, u_int param)
 1130 {
 1131         u_int freq;
 1132         sbintime_t period;
 1133         struct vt_window *vw = tm->tm_softc;
 1134         struct vt_device *vd = vw->vw_device;
 1135 
 1136         if ((param == 0) || ((param & 0xffff) == 0)) {
 1137                 vtterm_bell(tm);
 1138                 return;
 1139         }
 1140 
 1141         period = ((param >> 16) & 0xffff) * SBT_1MS;
 1142         freq = 1193182 / (param & 0xffff);
 1143 
 1144         vtterm_devctl(vt_enable_bell, vd->vd_flags & VDF_QUIET_BELL,
 1145             freq, period);
 1146 
 1147         if (!vt_enable_bell)
 1148                 return;
 1149 
 1150         sysbeep(freq, period);
 1151 }
 1152 
 1153 static void
 1154 vtterm_cursor(struct terminal *tm, const term_pos_t *p)
 1155 {
 1156         struct vt_window *vw = tm->tm_softc;
 1157 
 1158         vtbuf_cursor_position(&vw->vw_buf, p);
 1159 }
 1160 
 1161 static void
 1162 vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c)
 1163 {
 1164         struct vt_window *vw = tm->tm_softc;
 1165 
 1166         vtbuf_putchar(&vw->vw_buf, p, c);
 1167 }
 1168 
 1169 static void
 1170 vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c)
 1171 {
 1172         struct vt_window *vw = tm->tm_softc;
 1173 
 1174         vtbuf_fill(&vw->vw_buf, r, c);
 1175 }
 1176 
 1177 static void
 1178 vtterm_copy(struct terminal *tm, const term_rect_t *r,
 1179     const term_pos_t *p)
 1180 {
 1181         struct vt_window *vw = tm->tm_softc;
 1182 
 1183         vtbuf_copy(&vw->vw_buf, r, p);
 1184 }
 1185 
 1186 static void
 1187 vtterm_param(struct terminal *tm, int cmd, unsigned int arg)
 1188 {
 1189         struct vt_window *vw = tm->tm_softc;
 1190 
 1191         switch (cmd) {
 1192         case TP_SETLOCALCURSOR:
 1193                 /*
 1194                  * 0 means normal (usually block), 1 means hidden, and
 1195                  * 2 means blinking (always block) for compatibility with
 1196                  * syscons.  We don't support any changes except hiding,
 1197                  * so must map 2 to 0.
 1198                  */
 1199                 arg = (arg == 1) ? 0 : 1;
 1200                 /* FALLTHROUGH */
 1201         case TP_SHOWCURSOR:
 1202                 vtbuf_cursor_visibility(&vw->vw_buf, arg);
 1203                 vt_resume_flush_timer(vw, 0);
 1204                 break;
 1205         case TP_MOUSE:
 1206                 vw->vw_mouse_level = arg;
 1207                 break;
 1208         case TP_SETBELLPD:
 1209                 vw->vw_bell_pitch = TP_SETBELLPD_PITCH(arg);
 1210                 vw->vw_bell_duration =
 1211                     TICKS_2_MSEC(TP_SETBELLPD_DURATION(arg)) * SBT_1MS;
 1212                 break;
 1213         }
 1214 }
 1215 
 1216 void
 1217 vt_determine_colors(term_char_t c, int cursor,
 1218     term_color_t *fg, term_color_t *bg)
 1219 {
 1220         term_color_t tmp;
 1221         int invert;
 1222 
 1223         invert = 0;
 1224 
 1225         *fg = TCHAR_FGCOLOR(c);
 1226         if (TCHAR_FORMAT(c) & TF_BOLD)
 1227                 *fg = TCOLOR_LIGHT(*fg);
 1228         *bg = TCHAR_BGCOLOR(c);
 1229         if (TCHAR_FORMAT(c) & TF_BLINK)
 1230                 *bg = TCOLOR_LIGHT(*bg);
 1231 
 1232         if (TCHAR_FORMAT(c) & TF_REVERSE)
 1233                 invert ^= 1;
 1234         if (cursor)
 1235                 invert ^= 1;
 1236 
 1237         if (invert) {
 1238                 tmp = *fg;
 1239                 *fg = *bg;
 1240                 *bg = tmp;
 1241         }
 1242 }
 1243 
 1244 #ifndef SC_NO_CUTPASTE
 1245 int
 1246 vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area)
 1247 {
 1248         unsigned int mx, my;
 1249 
 1250         /*
 1251          * We use the cursor position saved during the current refresh,
 1252          * in case the cursor moved since.
 1253          */
 1254         mx = vd->vd_mx_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_col;
 1255         my = vd->vd_my_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_row;
 1256 
 1257         if (mx >= area->tr_end.tp_col ||
 1258             mx + vd->vd_mcursor->width <= area->tr_begin.tp_col ||
 1259             my >= area->tr_end.tp_row ||
 1260             my + vd->vd_mcursor->height <= area->tr_begin.tp_row)
 1261                 return (0);
 1262         return (1);
 1263 }
 1264 
 1265 static void
 1266 vt_mark_mouse_position_as_dirty(struct vt_device *vd, int locked)
 1267 {
 1268         term_rect_t area;
 1269         struct vt_window *vw;
 1270         struct vt_font *vf;
 1271         int x, y;
 1272 
 1273         vw = vd->vd_curwindow;
 1274         vf = vw->vw_font;
 1275 
 1276         x = vd->vd_mx_drawn;
 1277         y = vd->vd_my_drawn;
 1278 
 1279         if (vf != NULL) {
 1280                 area.tr_begin.tp_col = x / vf->vf_width;
 1281                 area.tr_begin.tp_row = y / vf->vf_height;
 1282                 area.tr_end.tp_col =
 1283                     ((x + vd->vd_mcursor->width) / vf->vf_width) + 1;
 1284                 area.tr_end.tp_row =
 1285                     ((y + vd->vd_mcursor->height) / vf->vf_height) + 1;
 1286         } else {
 1287                 /*
 1288                  * No font loaded (ie. vt_vga operating in textmode).
 1289                  *
 1290                  * FIXME: This fake area needs to be revisited once the
 1291                  * mouse cursor is supported in vt_vga's textmode.
 1292                  */
 1293                 area.tr_begin.tp_col = x;
 1294                 area.tr_begin.tp_row = y;
 1295                 area.tr_end.tp_col = x + 2;
 1296                 area.tr_end.tp_row = y + 2;
 1297         }
 1298 
 1299         if (!locked)
 1300                 vtbuf_lock(&vw->vw_buf);
 1301         if (vd->vd_driver->vd_invalidate_text)
 1302                 vd->vd_driver->vd_invalidate_text(vd, &area);
 1303         vtbuf_dirty(&vw->vw_buf, &area);
 1304         if (!locked)
 1305                 vtbuf_unlock(&vw->vw_buf);
 1306 }
 1307 #endif
 1308 
 1309 static void
 1310 vt_set_border(struct vt_device *vd, const term_rect_t *area,
 1311     term_color_t c)
 1312 {
 1313         vd_drawrect_t *drawrect = vd->vd_driver->vd_drawrect;
 1314 
 1315         if (drawrect == NULL)
 1316                 return;
 1317 
 1318         /* Top bar */
 1319         if (area->tr_begin.tp_row > 0)
 1320                 drawrect(vd, 0, 0, vd->vd_width - 1,
 1321                     area->tr_begin.tp_row - 1, 1, c);
 1322 
 1323         /* Left bar */
 1324         if (area->tr_begin.tp_col > 0)
 1325                 drawrect(vd, 0, area->tr_begin.tp_row,
 1326                     area->tr_begin.tp_col - 1, area->tr_end.tp_row - 1, 1, c);
 1327 
 1328         /* Right bar */
 1329         if (area->tr_end.tp_col < vd->vd_width)
 1330                 drawrect(vd, area->tr_end.tp_col, area->tr_begin.tp_row,
 1331                     vd->vd_width - 1, area->tr_end.tp_row - 1, 1, c);
 1332 
 1333         /* Bottom bar */
 1334         if (area->tr_end.tp_row < vd->vd_height)
 1335                 drawrect(vd, 0, area->tr_end.tp_row, vd->vd_width - 1,
 1336                     vd->vd_height - 1, 1, c);
 1337 }
 1338 
 1339 static int
 1340 vt_flush(struct vt_device *vd)
 1341 {
 1342         struct vt_window *vw;
 1343         struct vt_font *vf;
 1344         term_rect_t tarea;
 1345 #ifndef SC_NO_CUTPASTE
 1346         int cursor_was_shown, cursor_moved;
 1347 #endif
 1348 
 1349         vw = vd->vd_curwindow;
 1350         if (vw == NULL)
 1351                 return (0);
 1352 
 1353         if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
 1354                 return (0);
 1355 
 1356         vf = vw->vw_font;
 1357         if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL))
 1358                 return (0);
 1359 
 1360         vtbuf_lock(&vw->vw_buf);
 1361 
 1362 #ifndef SC_NO_CUTPASTE
 1363         cursor_was_shown = vd->vd_mshown;
 1364         cursor_moved = (vd->vd_mx != vd->vd_mx_drawn ||
 1365             vd->vd_my != vd->vd_my_drawn);
 1366 
 1367         /* Check if the cursor should be displayed or not. */
 1368         if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */
 1369             !(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed.      */
 1370             !kdb_active && !KERNEL_PANICKED()) {  /* DDB inactive.          */
 1371                 vd->vd_mshown = 1;
 1372         } else {
 1373                 vd->vd_mshown = 0;
 1374         }
 1375 
 1376         /*
 1377          * If the cursor changed display state or moved, we must mark
 1378          * the old position as dirty, so that it's erased.
 1379          */
 1380         if (cursor_was_shown != vd->vd_mshown ||
 1381             (vd->vd_mshown && cursor_moved))
 1382                 vt_mark_mouse_position_as_dirty(vd, true);
 1383 
 1384         /*
 1385          * Save position of the mouse cursor. It's used by backends to
 1386          * know where to draw the cursor and during the next refresh to
 1387          * erase the previous position.
 1388          */
 1389         vd->vd_mx_drawn = vd->vd_mx;
 1390         vd->vd_my_drawn = vd->vd_my;
 1391 
 1392         /*
 1393          * If the cursor is displayed and has moved since last refresh,
 1394          * mark the new position as dirty.
 1395          */
 1396         if (vd->vd_mshown && cursor_moved)
 1397                 vt_mark_mouse_position_as_dirty(vd, true);
 1398 #endif
 1399 
 1400         vtbuf_undirty(&vw->vw_buf, &tarea);
 1401 
 1402         /* Force a full redraw when the screen contents might be invalid. */
 1403         if (vd->vd_flags & (VDF_INVALID | VDF_SUSPENDED)) {
 1404                 const teken_attr_t *a;
 1405 
 1406                 vd->vd_flags &= ~VDF_INVALID;
 1407 
 1408                 a = teken_get_curattr(&vw->vw_terminal->tm_emulator);
 1409                 vt_set_border(vd, &vw->vw_draw_area, a->ta_bgcolor);
 1410                 vt_termrect(vd, vf, &tarea);
 1411                 if (vd->vd_driver->vd_invalidate_text)
 1412                         vd->vd_driver->vd_invalidate_text(vd, &tarea);
 1413                 if (vt_draw_logo_cpus)
 1414                         vtterm_draw_cpu_logos(vd);
 1415         }
 1416 
 1417         if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) {
 1418                 vd->vd_driver->vd_bitblt_text(vd, vw, &tarea);
 1419                 vtbuf_unlock(&vw->vw_buf);
 1420                 return (1);
 1421         }
 1422 
 1423         vtbuf_unlock(&vw->vw_buf);
 1424         return (0);
 1425 }
 1426 
 1427 static void
 1428 vt_timer(void *arg)
 1429 {
 1430         struct vt_device *vd;
 1431         int changed;
 1432 
 1433         vd = arg;
 1434         /* Update screen if required. */
 1435         changed = vt_flush(vd);
 1436 
 1437         /* Schedule for next update. */
 1438         if (changed)
 1439                 vt_schedule_flush(vd, 0);
 1440         else
 1441                 vd->vd_timer_armed = 0;
 1442 }
 1443 
 1444 static void
 1445 vtterm_pre_input(struct terminal *tm)
 1446 {
 1447         struct vt_window *vw = tm->tm_softc;
 1448 
 1449         vtbuf_lock(&vw->vw_buf);
 1450 }
 1451 
 1452 static void
 1453 vtterm_post_input(struct terminal *tm)
 1454 {
 1455         struct vt_window *vw = tm->tm_softc;
 1456 
 1457         vtbuf_unlock(&vw->vw_buf);
 1458         vt_resume_flush_timer(vw, 0);
 1459 }
 1460 
 1461 static void
 1462 vtterm_done(struct terminal *tm)
 1463 {
 1464         struct vt_window *vw = tm->tm_softc;
 1465         struct vt_device *vd = vw->vw_device;
 1466 
 1467         if (kdb_active || KERNEL_PANICKED()) {
 1468                 /* Switch to the debugger. */
 1469                 if (vd->vd_curwindow != vw) {
 1470                         vd->vd_curwindow = vw;
 1471                         vd->vd_flags |= VDF_INVALID;
 1472                         if (vd->vd_driver->vd_postswitch)
 1473                                 vd->vd_driver->vd_postswitch(vd);
 1474                 }
 1475                 vd->vd_flags &= ~VDF_SPLASH;
 1476                 vt_flush(vd);
 1477         } else if (!(vd->vd_flags & VDF_ASYNC)) {
 1478                 vt_flush(vd);
 1479         }
 1480 }
 1481 
 1482 #ifdef DEV_SPLASH
 1483 static void
 1484 vtterm_splash(struct vt_device *vd)
 1485 {
 1486         vt_axis_t top, left;
 1487 
 1488         /* Display a nice boot splash. */
 1489         if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) {
 1490                 top = (vd->vd_height - vt_logo_height) / 2;
 1491                 left = (vd->vd_width - vt_logo_width) / 2;
 1492                 switch (vt_logo_depth) {
 1493                 case 1:
 1494                         /* XXX: Unhardcode colors! */
 1495                         vd->vd_driver->vd_bitblt_bmp(vd, vd->vd_curwindow,
 1496                             vt_logo_image, NULL, vt_logo_width, vt_logo_height,
 1497                             left, top, TC_WHITE, TC_BLACK);
 1498                 }
 1499                 vd->vd_flags |= VDF_SPLASH;
 1500         }
 1501 }
 1502 #endif
 1503 
 1504 static struct vt_font *
 1505 parse_font_info_static(struct font_info *fi)
 1506 {
 1507         struct vt_font *vfp;
 1508         uintptr_t ptr;
 1509         uint32_t checksum;
 1510 
 1511         if (fi == NULL)
 1512                 return (NULL);
 1513 
 1514         ptr = (uintptr_t)fi;
 1515         /*
 1516          * Compute and verify checksum. The total sum of all the fields
 1517          * must be 0.
 1518          */
 1519         checksum = fi->fi_width;
 1520         checksum += fi->fi_height;
 1521         checksum += fi->fi_bitmap_size;
 1522         for (unsigned i = 0; i < VFNT_MAPS; i++)
 1523                 checksum += fi->fi_map_count[i];
 1524 
 1525         if (checksum + fi->fi_checksum != 0)
 1526                 return (NULL);
 1527 
 1528         ptr += sizeof(struct font_info);
 1529         ptr = roundup2(ptr, 8);
 1530 
 1531         vfp = &vt_font_loader;
 1532         vfp->vf_height = fi->fi_height;
 1533         vfp->vf_width = fi->fi_width;
 1534         /* This is default font, set refcount 1 to disable removal. */
 1535         vfp->vf_refcount = 1;
 1536         for (unsigned i = 0; i < VFNT_MAPS; i++) {
 1537                 if (fi->fi_map_count[i] == 0)
 1538                         continue;
 1539                 vfp->vf_map_count[i] = fi->fi_map_count[i];
 1540                 vfp->vf_map[i] = (vfnt_map_t *)ptr;
 1541                 ptr += (fi->fi_map_count[i] * sizeof(vfnt_map_t));
 1542                 ptr = roundup2(ptr, 8);
 1543         }
 1544         vfp->vf_bytes = (uint8_t *)ptr;
 1545         return (vfp);
 1546 }
 1547 
 1548 /*
 1549  * Set up default font with allocated data structures.
 1550  * However, we can not set refcount here, because it is already set and
 1551  * incremented in vtterm_cnprobe() to avoid being released by font load from
 1552  * userland.
 1553  */
 1554 static struct vt_font *
 1555 parse_font_info(struct font_info *fi)
 1556 {
 1557         struct vt_font *vfp;
 1558         uintptr_t ptr;
 1559         uint32_t checksum;
 1560         size_t size;
 1561 
 1562         if (fi == NULL)
 1563                 return (NULL);
 1564 
 1565         ptr = (uintptr_t)fi;
 1566         /*
 1567          * Compute and verify checksum. The total sum of all the fields
 1568          * must be 0.
 1569          */
 1570         checksum = fi->fi_width;
 1571         checksum += fi->fi_height;
 1572         checksum += fi->fi_bitmap_size;
 1573         for (unsigned i = 0; i < VFNT_MAPS; i++)
 1574                 checksum += fi->fi_map_count[i];
 1575 
 1576         if (checksum + fi->fi_checksum != 0)
 1577                 return (NULL);
 1578 
 1579         ptr += sizeof(struct font_info);
 1580         ptr = roundup2(ptr, 8);
 1581 
 1582         vfp = &vt_font_loader;
 1583         vfp->vf_height = fi->fi_height;
 1584         vfp->vf_width = fi->fi_width;
 1585         for (unsigned i = 0; i < VFNT_MAPS; i++) {
 1586                 if (fi->fi_map_count[i] == 0)
 1587                         continue;
 1588                 vfp->vf_map_count[i] = fi->fi_map_count[i];
 1589                 size = fi->fi_map_count[i] * sizeof(vfnt_map_t);
 1590                 vfp->vf_map[i] = malloc(size, M_VT, M_WAITOK | M_ZERO);
 1591                 bcopy((vfnt_map_t *)ptr, vfp->vf_map[i], size);
 1592                 ptr += size;
 1593                 ptr = roundup2(ptr, 8);
 1594         }
 1595         vfp->vf_bytes = malloc(fi->fi_bitmap_size, M_VT, M_WAITOK | M_ZERO);
 1596         bcopy((uint8_t *)ptr, vfp->vf_bytes, fi->fi_bitmap_size);
 1597         return (vfp);
 1598 }
 1599 
 1600 static void
 1601 vt_init_font(void *arg)
 1602 {
 1603         caddr_t kmdp;
 1604         struct font_info *fi;
 1605         struct vt_font *font;
 1606 
 1607         kmdp = preload_search_by_type("elf kernel");
 1608         if (kmdp == NULL)
 1609                 kmdp = preload_search_by_type("elf64 kernel");
 1610         fi = MD_FETCH(kmdp, MODINFOMD_FONT, struct font_info *);
 1611 
 1612         font = parse_font_info(fi);
 1613         if (font != NULL)
 1614                 vt_font_assigned = font;
 1615 }
 1616 
 1617 SYSINIT(vt_init_font, SI_SUB_KMEM, SI_ORDER_ANY, vt_init_font, &vt_consdev);
 1618 
 1619 static void
 1620 vt_init_font_static(void)
 1621 {
 1622         caddr_t kmdp;
 1623         struct font_info *fi;
 1624         struct vt_font *font;
 1625 
 1626         kmdp = preload_search_by_type("elf kernel");
 1627         if (kmdp == NULL)
 1628                 kmdp = preload_search_by_type("elf64 kernel");
 1629         fi = MD_FETCH(kmdp, MODINFOMD_FONT, struct font_info *);
 1630 
 1631         font = parse_font_info_static(fi);
 1632         if (font != NULL)
 1633                 vt_font_assigned = font;
 1634 }
 1635 
 1636 static void
 1637 vtterm_cnprobe(struct terminal *tm, struct consdev *cp)
 1638 {
 1639         struct vt_driver *vtd, **vtdlist, *vtdbest = NULL;
 1640         struct vt_window *vw = tm->tm_softc;
 1641         struct vt_device *vd = vw->vw_device;
 1642         struct winsize wsz;
 1643         const term_attr_t *a;
 1644 
 1645         if (!vty_enabled(VTY_VT))
 1646                 return;
 1647 
 1648         if (vd->vd_flags & VDF_INITIALIZED)
 1649                 /* Initialization already done. */
 1650                 return;
 1651 
 1652         SET_FOREACH(vtdlist, vt_drv_set) {
 1653                 vtd = *vtdlist;
 1654                 if (vtd->vd_probe == NULL)
 1655                         continue;
 1656                 if (vtd->vd_probe(vd) == CN_DEAD)
 1657                         continue;
 1658                 if ((vtdbest == NULL) ||
 1659                     (vtd->vd_priority > vtdbest->vd_priority))
 1660                         vtdbest = vtd;
 1661         }
 1662         if (vtdbest == NULL) {
 1663                 cp->cn_pri = CN_DEAD;
 1664                 vd->vd_flags |= VDF_DEAD;
 1665         } else {
 1666                 vd->vd_driver = vtdbest;
 1667                 cp->cn_pri = vd->vd_driver->vd_init(vd);
 1668         }
 1669 
 1670         /* Check if driver's vt_init return CN_DEAD. */
 1671         if (cp->cn_pri == CN_DEAD) {
 1672                 vd->vd_flags |= VDF_DEAD;
 1673         }
 1674 
 1675         /* Initialize any early-boot keyboard drivers */
 1676         kbd_configure(KB_CONF_PROBE_ONLY);
 1677 
 1678         vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1);
 1679         vd->vd_windows[VT_CONSWINDOW] = vw;
 1680         sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw));
 1681 
 1682         vt_init_font_static();
 1683 
 1684         /* Attach default font if not in TEXTMODE. */
 1685         if ((vd->vd_flags & VDF_TEXTMODE) == 0) {
 1686                 vw->vw_font = vtfont_ref(vt_font_assigned);
 1687                 vt_compute_drawable_area(vw);
 1688         }
 1689 
 1690         /*
 1691          * The original screen size was faked (_VTDEFW x _VTDEFH). Now
 1692          * that we have the real viewable size, fix it in the static
 1693          * buffer.
 1694          */
 1695         if (vd->vd_width != 0 && vd->vd_height != 0)
 1696                 vt_termsize(vd, vw->vw_font, &vw->vw_buf.vb_scr_size);
 1697 
 1698         /* We need to access terminal attributes from vtbuf */
 1699         vw->vw_buf.vb_terminal = tm;
 1700         vtbuf_init_early(&vw->vw_buf);
 1701         vt_winsize(vd, vw->vw_font, &wsz);
 1702         a = teken_get_curattr(&tm->tm_emulator);
 1703         terminal_set_winsize_blank(tm, &wsz, 1, a);
 1704 
 1705         if (vtdbest != NULL) {
 1706 #ifdef DEV_SPLASH
 1707                 if (!vt_splash_cpu)
 1708                         vtterm_splash(vd);
 1709 #endif
 1710                 vd->vd_flags |= VDF_INITIALIZED;
 1711         }
 1712 }
 1713 
 1714 static int
 1715 vtterm_cngetc(struct terminal *tm)
 1716 {
 1717         struct vt_window *vw = tm->tm_softc;
 1718         struct vt_device *vd = vw->vw_device;
 1719         keyboard_t *kbd;
 1720         u_int c;
 1721 
 1722         if (vw->vw_kbdsq && *vw->vw_kbdsq)
 1723                 return (*vw->vw_kbdsq++);
 1724 
 1725         /* Make sure the splash screen is not there. */
 1726         if (vd->vd_flags & VDF_SPLASH) {
 1727                 /* Remove splash */
 1728                 vd->vd_flags &= ~VDF_SPLASH;
 1729                 /* Mark screen as invalid to force update */
 1730                 vd->vd_flags |= VDF_INVALID;
 1731                 vt_flush(vd);
 1732         }
 1733 
 1734         /* Stripped down keyboard handler. */
 1735         if ((kbd = vd->vd_keyboard) == NULL)
 1736                 return (-1);
 1737 
 1738         /* Force keyboard input mode to K_XLATE */
 1739         vw->vw_kbdmode = K_XLATE;
 1740         vt_update_kbd_mode(vw, kbd);
 1741 
 1742         /* Switch the keyboard to polling to make it work here. */
 1743         kbdd_poll(kbd, TRUE);
 1744         c = kbdd_read_char(kbd, 0);
 1745         kbdd_poll(kbd, FALSE);
 1746         if (c & RELKEY)
 1747                 return (-1);
 1748 
 1749         if (vw->vw_flags & VWF_SCROLL) {
 1750                 vt_scrollmode_kbdevent(vw, c, 1/* Console mode */);
 1751                 vt_flush(vd);
 1752                 return (-1);
 1753         }
 1754 
 1755         /* Stripped down handling of vt_kbdevent(), without locking, etc. */
 1756         if (c & SPCLKEY) {
 1757                 switch (c) {
 1758                 case SPCLKEY | SLK:
 1759                         vt_save_kbd_state(vw, kbd);
 1760                         if (vw->vw_kbdstate & SLKED) {
 1761                                 /* Turn scrolling on. */
 1762                                 vw->vw_flags |= VWF_SCROLL;
 1763                                 VTBUF_SLCK_ENABLE(&vw->vw_buf);
 1764                         } else {
 1765                                 /* Turn scrolling off. */
 1766                                 vt_scroll(vw, 0, VHS_END);
 1767                                 vw->vw_flags &= ~VWF_SCROLL;
 1768                                 VTBUF_SLCK_DISABLE(&vw->vw_buf);
 1769                         }
 1770                         break;
 1771                 /* XXX: KDB can handle history. */
 1772                 case SPCLKEY | FKEY | F(50): /* Arrow up. */
 1773                         vw->vw_kbdsq = "\x1b[A";
 1774                         break;
 1775                 case SPCLKEY | FKEY | F(58): /* Arrow down. */
 1776                         vw->vw_kbdsq = "\x1b[B";
 1777                         break;
 1778                 case SPCLKEY | FKEY | F(55): /* Arrow right. */
 1779                         vw->vw_kbdsq = "\x1b[C";
 1780                         break;
 1781                 case SPCLKEY | FKEY | F(53): /* Arrow left. */
 1782                         vw->vw_kbdsq = "\x1b[D";
 1783                         break;
 1784                 }
 1785 
 1786                 /* Force refresh to make scrollback work. */
 1787                 vt_flush(vd);
 1788         } else if (KEYFLAGS(c) == 0) {
 1789                 return (KEYCHAR(c));
 1790         }
 1791 
 1792         if (vw->vw_kbdsq && *vw->vw_kbdsq)
 1793                 return (*vw->vw_kbdsq++);
 1794 
 1795         return (-1);
 1796 }
 1797 
 1798 /*
 1799  * These two do most of what we want to do in vtterm_cnungrab, but without
 1800  * actually switching windows.  This is necessary for, e.g.,
 1801  * vt_allocate_keyboard() to get the current keyboard into the state it needs to
 1802  * be in without damaging the device's window state.
 1803  *
 1804  * Both return the current grab count, though it's only used in vtterm_cnungrab.
 1805  */
 1806 static int
 1807 vtterm_cngrab_noswitch(struct vt_device *vd, struct vt_window *vw)
 1808 {
 1809         keyboard_t *kbd;
 1810 
 1811         if (vw->vw_grabbed++ > 0)
 1812                 return (vw->vw_grabbed);
 1813 
 1814         if ((kbd = vd->vd_keyboard) == NULL)
 1815                 return (1);
 1816 
 1817         /*
 1818          * Make sure the keyboard is accessible even when the kbd device
 1819          * driver is disabled.
 1820          */
 1821         kbdd_enable(kbd);
 1822 
 1823         /* We shall always use the keyboard in the XLATE mode here. */
 1824         vw->vw_prev_kbdmode = vw->vw_kbdmode;
 1825         vw->vw_kbdmode = K_XLATE;
 1826         vt_update_kbd_mode(vw, kbd);
 1827 
 1828         kbdd_poll(kbd, TRUE);
 1829         return (1);
 1830 }
 1831 
 1832 static int
 1833 vtterm_cnungrab_noswitch(struct vt_device *vd, struct vt_window *vw)
 1834 {
 1835         keyboard_t *kbd;
 1836 
 1837         if (--vw->vw_grabbed > 0)
 1838                 return (vw->vw_grabbed);
 1839 
 1840         if ((kbd = vd->vd_keyboard) == NULL)
 1841                 return (0);
 1842 
 1843         kbdd_poll(kbd, FALSE);
 1844 
 1845         vw->vw_kbdmode = vw->vw_prev_kbdmode;
 1846         vt_update_kbd_mode(vw, kbd);
 1847         kbdd_disable(kbd);
 1848         return (0);
 1849 }
 1850 
 1851 static void
 1852 vtterm_cngrab(struct terminal *tm)
 1853 {
 1854         struct vt_device *vd;
 1855         struct vt_window *vw;
 1856 
 1857         vw = tm->tm_softc;
 1858         vd = vw->vw_device;
 1859 
 1860         /* To be restored after we ungrab. */
 1861         if (vd->vd_grabwindow == NULL)
 1862                 vd->vd_grabwindow = vd->vd_curwindow;
 1863 
 1864         if (!cold)
 1865                 vt_window_switch(vw);
 1866 
 1867         vtterm_cngrab_noswitch(vd, vw);
 1868 }
 1869 
 1870 static void
 1871 vtterm_cnungrab(struct terminal *tm)
 1872 {
 1873         struct vt_device *vd;
 1874         struct vt_window *vw;
 1875 
 1876         vw = tm->tm_softc;
 1877         vd = vw->vw_device;
 1878 
 1879         MPASS(vd->vd_grabwindow != NULL);
 1880         if (vtterm_cnungrab_noswitch(vd, vw) != 0)
 1881                 return;
 1882 
 1883         if (!cold && vd->vd_grabwindow != vw)
 1884                 vt_window_switch(vd->vd_grabwindow);
 1885 
 1886         vd->vd_grabwindow = NULL;
 1887 }
 1888 
 1889 static void
 1890 vtterm_opened(struct terminal *tm, int opened)
 1891 {
 1892         struct vt_window *vw = tm->tm_softc;
 1893         struct vt_device *vd = vw->vw_device;
 1894 
 1895         VT_LOCK(vd);
 1896         vd->vd_flags &= ~VDF_SPLASH;
 1897         if (opened)
 1898                 vw->vw_flags |= VWF_OPENED;
 1899         else {
 1900                 vw->vw_flags &= ~VWF_OPENED;
 1901                 /* TODO: finish ACQ/REL */
 1902         }
 1903         VT_UNLOCK(vd);
 1904 }
 1905 
 1906 static int
 1907 vt_change_font(struct vt_window *vw, struct vt_font *vf)
 1908 {
 1909         struct vt_device *vd = vw->vw_device;
 1910         struct terminal *tm = vw->vw_terminal;
 1911         term_pos_t size;
 1912         struct winsize wsz;
 1913 
 1914         /*
 1915          * Changing fonts.
 1916          *
 1917          * Changing fonts is a little tricky.  We must prevent
 1918          * simultaneous access to the device, so we must stop
 1919          * the display timer and the terminal from accessing.
 1920          * We need to switch fonts and grow our screen buffer.
 1921          *
 1922          * XXX: Right now the code uses terminal_mute() to
 1923          * prevent data from reaching the console driver while
 1924          * resizing the screen buffer.  This isn't elegant...
 1925          */
 1926 
 1927         VT_LOCK(vd);
 1928         if (vw->vw_flags & VWF_BUSY) {
 1929                 /* Another process is changing the font. */
 1930                 VT_UNLOCK(vd);
 1931                 return (EBUSY);
 1932         }
 1933         vw->vw_flags |= VWF_BUSY;
 1934         VT_UNLOCK(vd);
 1935 
 1936         vt_termsize(vd, vf, &size);
 1937         vt_winsize(vd, vf, &wsz);
 1938 
 1939         /* Grow the screen buffer and terminal. */
 1940         terminal_mute(tm, 1);
 1941         vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
 1942         terminal_set_winsize_blank(tm, &wsz, 0, NULL);
 1943         terminal_set_cursor(tm, &vw->vw_buf.vb_cursor);
 1944         terminal_mute(tm, 0);
 1945 
 1946         /* Actually apply the font to the current window. */
 1947         VT_LOCK(vd);
 1948         if (vw->vw_font != vf && vw->vw_font != NULL && vf != NULL) {
 1949                 /*
 1950                  * In case vt_change_font called to update size we don't need
 1951                  * to update font link.
 1952                  */
 1953                 vtfont_unref(vw->vw_font);
 1954                 vw->vw_font = vtfont_ref(vf);
 1955         }
 1956 
 1957         /*
 1958          * Compute the drawable area and move the mouse cursor inside
 1959          * it, in case the new area is smaller than the previous one.
 1960          */
 1961         vt_compute_drawable_area(vw);
 1962         vd->vd_mx = min(vd->vd_mx,
 1963             vw->vw_draw_area.tr_end.tp_col -
 1964             vw->vw_draw_area.tr_begin.tp_col - 1);
 1965         vd->vd_my = min(vd->vd_my,
 1966             vw->vw_draw_area.tr_end.tp_row -
 1967             vw->vw_draw_area.tr_begin.tp_row - 1);
 1968 
 1969         /* Force a full redraw the next timer tick. */
 1970         if (vd->vd_curwindow == vw) {
 1971                 vd->vd_flags |= VDF_INVALID;
 1972                 vt_resume_flush_timer(vw, 0);
 1973         }
 1974         vw->vw_flags &= ~VWF_BUSY;
 1975         VT_UNLOCK(vd);
 1976         return (0);
 1977 }
 1978 
 1979 static int
 1980 vt_proc_alive(struct vt_window *vw)
 1981 {
 1982         struct proc *p;
 1983 
 1984         if (vw->vw_smode.mode != VT_PROCESS)
 1985                 return (FALSE);
 1986 
 1987         if (vw->vw_proc) {
 1988                 if ((p = pfind(vw->vw_pid)) != NULL)
 1989                         PROC_UNLOCK(p);
 1990                 if (vw->vw_proc == p)
 1991                         return (TRUE);
 1992                 vw->vw_proc = NULL;
 1993                 vw->vw_smode.mode = VT_AUTO;
 1994                 DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid);
 1995                 vw->vw_pid = 0;
 1996         }
 1997         return (FALSE);
 1998 }
 1999 
 2000 static int
 2001 signal_vt_rel(struct vt_window *vw)
 2002 {
 2003 
 2004         if (vw->vw_smode.mode != VT_PROCESS)
 2005                 return (FALSE);
 2006         if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
 2007                 vw->vw_proc = NULL;
 2008                 vw->vw_pid = 0;
 2009                 return (TRUE);
 2010         }
 2011         vw->vw_flags |= VWF_SWWAIT_REL;
 2012         PROC_LOCK(vw->vw_proc);
 2013         kern_psignal(vw->vw_proc, vw->vw_smode.relsig);
 2014         PROC_UNLOCK(vw->vw_proc);
 2015         DPRINTF(1, "sending relsig to %d\n", vw->vw_pid);
 2016         return (TRUE);
 2017 }
 2018 
 2019 static int
 2020 signal_vt_acq(struct vt_window *vw)
 2021 {
 2022 
 2023         if (vw->vw_smode.mode != VT_PROCESS)
 2024                 return (FALSE);
 2025         if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
 2026                 cnavailable(vw->vw_terminal->consdev, FALSE);
 2027         if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
 2028                 vw->vw_proc = NULL;
 2029                 vw->vw_pid = 0;
 2030                 return (TRUE);
 2031         }
 2032         vw->vw_flags |= VWF_SWWAIT_ACQ;
 2033         PROC_LOCK(vw->vw_proc);
 2034         kern_psignal(vw->vw_proc, vw->vw_smode.acqsig);
 2035         PROC_UNLOCK(vw->vw_proc);
 2036         DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid);
 2037         return (TRUE);
 2038 }
 2039 
 2040 static int
 2041 finish_vt_rel(struct vt_window *vw, int release, int *s)
 2042 {
 2043 
 2044         if (vw->vw_flags & VWF_SWWAIT_REL) {
 2045                 vw->vw_flags &= ~VWF_SWWAIT_REL;
 2046                 if (release) {
 2047                         taskqueue_drain_timeout(taskqueue_thread, &vw->vw_timeout_task_dead);
 2048                         (void)vt_late_window_switch(vw->vw_switch_to);
 2049                 }
 2050                 return (0);
 2051         }
 2052         return (EINVAL);
 2053 }
 2054 
 2055 static int
 2056 finish_vt_acq(struct vt_window *vw)
 2057 {
 2058 
 2059         if (vw->vw_flags & VWF_SWWAIT_ACQ) {
 2060                 vw->vw_flags &= ~VWF_SWWAIT_ACQ;
 2061                 return (0);
 2062         }
 2063         return (EINVAL);
 2064 }
 2065 
 2066 #ifndef SC_NO_CUTPASTE
 2067 static void
 2068 vt_mouse_terminput_button(struct vt_device *vd, int button)
 2069 {
 2070         struct vt_window *vw;
 2071         struct vt_font *vf;
 2072         char mouseb[6] = "\x1B[M";
 2073         int i, x, y;
 2074 
 2075         vw = vd->vd_curwindow;
 2076         vf = vw->vw_font;
 2077 
 2078         /* Translate to char position. */
 2079         x = vd->vd_mx / vf->vf_width;
 2080         y = vd->vd_my / vf->vf_height;
 2081         /* Avoid overflow. */
 2082         x = MIN(x, 255 - '!');
 2083         y = MIN(y, 255 - '!');
 2084 
 2085         mouseb[3] = ' ' + button;
 2086         mouseb[4] = '!' + x;
 2087         mouseb[5] = '!' + y;
 2088 
 2089         for (i = 0; i < sizeof(mouseb); i++)
 2090                 terminal_input_char(vw->vw_terminal, mouseb[i]);
 2091 }
 2092 
 2093 static void
 2094 vt_mouse_terminput(struct vt_device *vd, int type, int x, int y, int event,
 2095     int cnt)
 2096 {
 2097 
 2098         switch (type) {
 2099         case MOUSE_BUTTON_EVENT:
 2100                 if (cnt > 0) {
 2101                         /* Mouse button pressed. */
 2102                         if (event & MOUSE_BUTTON1DOWN)
 2103                                 vt_mouse_terminput_button(vd, 0);
 2104                         if (event & MOUSE_BUTTON2DOWN)
 2105                                 vt_mouse_terminput_button(vd, 1);
 2106                         if (event & MOUSE_BUTTON3DOWN)
 2107                                 vt_mouse_terminput_button(vd, 2);
 2108                 } else {
 2109                         /* Mouse button released. */
 2110                         vt_mouse_terminput_button(vd, 3);
 2111                 }
 2112                 break;
 2113 #ifdef notyet
 2114         case MOUSE_MOTION_EVENT:
 2115                 if (mouse->u.data.z < 0) {
 2116                         /* Scroll up. */
 2117                         sc_mouse_input_button(vd, 64);
 2118                 } else if (mouse->u.data.z > 0) {
 2119                         /* Scroll down. */
 2120                         sc_mouse_input_button(vd, 65);
 2121                 }
 2122                 break;
 2123 #endif
 2124         }
 2125 }
 2126 
 2127 static void
 2128 vt_mouse_paste(void)
 2129 {
 2130         term_char_t *buf;
 2131         int i, len;
 2132 
 2133         len = VD_PASTEBUFLEN(main_vd);
 2134         buf = VD_PASTEBUF(main_vd);
 2135         len /= sizeof(term_char_t);
 2136         for (i = 0; i < len; i++) {
 2137                 if (TCHAR_CHARACTER(buf[i]) == '\0')
 2138                         continue;
 2139                 terminal_input_char(main_vd->vd_curwindow->vw_terminal,
 2140                     buf[i]);
 2141         }
 2142 }
 2143 
 2144 void
 2145 vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel)
 2146 {
 2147         struct vt_device *vd;
 2148         struct vt_window *vw;
 2149         struct vt_font *vf;
 2150         term_pos_t size;
 2151         int len, mark;
 2152 
 2153         vd = main_vd;
 2154         vw = vd->vd_curwindow;
 2155         vf = vw->vw_font;
 2156 
 2157         if (vw->vw_flags & (VWF_MOUSE_HIDE | VWF_GRAPHICS))
 2158                 /*
 2159                  * Either the mouse is disabled, or the window is in
 2160                  * "graphics mode". The graphics mode is usually set by
 2161                  * an X server, using the KDSETMODE ioctl.
 2162                  */
 2163                 return;
 2164 
 2165         if (vf == NULL) /* Text mode. */
 2166                 return;
 2167 
 2168         /*
 2169          * TODO: add flag about pointer position changed, to not redraw chars
 2170          * under mouse pointer when nothing changed.
 2171          */
 2172 
 2173         if (vw->vw_mouse_level > 0)
 2174                 vt_mouse_terminput(vd, type, x, y, event, cnt);
 2175 
 2176         switch (type) {
 2177         case MOUSE_ACTION:
 2178         case MOUSE_MOTION_EVENT:
 2179                 /* Movement */
 2180                 x += vd->vd_mx;
 2181                 y += vd->vd_my;
 2182 
 2183                 vt_termsize(vd, vf, &size);
 2184 
 2185                 /* Apply limits. */
 2186                 x = MAX(x, 0);
 2187                 y = MAX(y, 0);
 2188                 x = MIN(x, (size.tp_col * vf->vf_width) - 1);
 2189                 y = MIN(y, (size.tp_row * vf->vf_height) - 1);
 2190 
 2191                 vd->vd_mx = x;
 2192                 vd->vd_my = y;
 2193                 if (vd->vd_mstate & (MOUSE_BUTTON1DOWN | VT_MOUSE_EXTENDBUTTON))
 2194                         vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE,
 2195                             vd->vd_mx / vf->vf_width,
 2196                             vd->vd_my / vf->vf_height);
 2197 
 2198                 vt_resume_flush_timer(vw, 0);
 2199                 return; /* Done */
 2200         case MOUSE_BUTTON_EVENT:
 2201                 /* Buttons */
 2202                 break;
 2203         default:
 2204                 return; /* Done */
 2205         }
 2206 
 2207         switch (event) {
 2208         case MOUSE_BUTTON1DOWN:
 2209                 switch (cnt % 4) {
 2210                 case 0: /* up */
 2211                         mark = VTB_MARK_END;
 2212                         break;
 2213                 case 1: /* single click: start cut operation */
 2214                         mark = VTB_MARK_START;
 2215                         break;
 2216                 case 2: /* double click: cut a word */
 2217                         mark = VTB_MARK_WORD;
 2218                         break;
 2219                 default:        /* triple click: cut a line */
 2220                         mark = VTB_MARK_ROW;
 2221                         break;
 2222                 }
 2223                 break;
 2224         case VT_MOUSE_PASTEBUTTON:
 2225                 switch (cnt) {
 2226                 case 0: /* up */
 2227                         break;
 2228                 default:
 2229                         vt_mouse_paste();
 2230                         /* clear paste buffer selection after paste */
 2231                         vtbuf_set_mark(&vw->vw_buf, VTB_MARK_START,
 2232                             vd->vd_mx / vf->vf_width,
 2233                             vd->vd_my / vf->vf_height);
 2234                         break;
 2235                 }
 2236                 return; /* Done */
 2237         case VT_MOUSE_EXTENDBUTTON:
 2238                 switch (cnt) {
 2239                 case 0: /* up */
 2240                         if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN))
 2241                                 mark = VTB_MARK_EXTEND;
 2242                         else
 2243                                 mark = VTB_MARK_NONE;
 2244                         break;
 2245                 default:
 2246                         mark = VTB_MARK_EXTEND;
 2247                         break;
 2248                 }
 2249                 break;
 2250         default:
 2251                 return; /* Done */
 2252         }
 2253 
 2254         /* Save buttons state. */
 2255         if (cnt > 0)
 2256                 vd->vd_mstate |= event;
 2257         else
 2258                 vd->vd_mstate &= ~event;
 2259 
 2260         if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width,
 2261             vd->vd_my / vf->vf_height) == 1) {
 2262                 /*
 2263                  * We have something marked to copy, so update pointer to
 2264                  * window with selection.
 2265                  */
 2266                 vt_resume_flush_timer(vw, 0);
 2267 
 2268                 switch (mark) {
 2269                 case VTB_MARK_END:
 2270                 case VTB_MARK_WORD:
 2271                 case VTB_MARK_ROW:
 2272                 case VTB_MARK_EXTEND:
 2273                         break;
 2274                 default:
 2275                         /* Other types of mark do not require to copy data. */
 2276                         return;
 2277                 }
 2278 
 2279                 /* Get current selection size in bytes. */
 2280                 len = vtbuf_get_marked_len(&vw->vw_buf);
 2281                 if (len <= 0)
 2282                         return;
 2283 
 2284                 /* Reallocate buffer only if old one is too small. */
 2285                 if (len > VD_PASTEBUFSZ(vd)) {
 2286                         VD_PASTEBUF(vd) = realloc(VD_PASTEBUF(vd), len, M_VT,
 2287                             M_WAITOK | M_ZERO);
 2288                         /* Update buffer size. */
 2289                         VD_PASTEBUFSZ(vd) = len;
 2290                 }
 2291                 /* Request copy/paste buffer data, no more than `len' */
 2292                 vtbuf_extract_marked(&vw->vw_buf, VD_PASTEBUF(vd), len, mark);
 2293 
 2294                 VD_PASTEBUFLEN(vd) = len;
 2295 
 2296                 /* XXX VD_PASTEBUF(vd) have to be freed on shutdown/unload. */
 2297         }
 2298 }
 2299 
 2300 void
 2301 vt_mouse_state(int show)
 2302 {
 2303         struct vt_device *vd;
 2304         struct vt_window *vw;
 2305 
 2306         vd = main_vd;
 2307         vw = vd->vd_curwindow;
 2308 
 2309         switch (show) {
 2310         case VT_MOUSE_HIDE:
 2311                 vw->vw_flags |= VWF_MOUSE_HIDE;
 2312                 break;
 2313         case VT_MOUSE_SHOW:
 2314                 vw->vw_flags &= ~VWF_MOUSE_HIDE;
 2315                 break;
 2316         }
 2317 
 2318         /* Mark mouse position as dirty. */
 2319         vt_mark_mouse_position_as_dirty(vd, false);
 2320         vt_resume_flush_timer(vw, 0);
 2321 }
 2322 #endif
 2323 
 2324 static int
 2325 vtterm_mmap(struct terminal *tm, vm_ooffset_t offset, vm_paddr_t * paddr,
 2326     int nprot, vm_memattr_t *memattr)
 2327 {
 2328         struct vt_window *vw = tm->tm_softc;
 2329         struct vt_device *vd = vw->vw_device;
 2330 
 2331         if (vd->vd_driver->vd_fb_mmap)
 2332                 return (vd->vd_driver->vd_fb_mmap(vd, offset, paddr, nprot,
 2333                     memattr));
 2334 
 2335         return (ENXIO);
 2336 }
 2337 
 2338 static int
 2339 vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
 2340     struct thread *td)
 2341 {
 2342         struct vt_window *vw = tm->tm_softc;
 2343         struct vt_device *vd = vw->vw_device;
 2344         keyboard_t *kbd;
 2345         int error, i, s;
 2346 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
 2347     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
 2348         int ival;
 2349 
 2350         switch (cmd) {
 2351         case _IO('v', 4):
 2352                 cmd = VT_RELDISP;
 2353                 break;
 2354         case _IO('v', 5):
 2355                 cmd = VT_ACTIVATE;
 2356                 break;
 2357         case _IO('v', 6):
 2358                 cmd = VT_WAITACTIVE;
 2359                 break;
 2360         case _IO('K', 20):
 2361                 cmd = KDSKBSTATE;
 2362                 break;
 2363         case _IO('K', 67):
 2364                 cmd = KDSETRAD;
 2365                 break;
 2366         case _IO('K', 7):
 2367                 cmd = KDSKBMODE;
 2368                 break;
 2369         case _IO('K', 8):
 2370                 cmd = KDMKTONE;
 2371                 break;
 2372         case _IO('K', 10):
 2373                 cmd = KDSETMODE;
 2374                 break;
 2375         case _IO('K', 13):
 2376                 cmd = KDSBORDER;
 2377                 break;
 2378         case _IO('K', 63):
 2379                 cmd = KIOCSOUND;
 2380                 break;
 2381         case _IO('K', 66):
 2382                 cmd = KDSETLED;
 2383                 break;
 2384         case _IO('c', 104):
 2385                 cmd = CONS_SETWINORG;
 2386                 break;
 2387         case _IO('c', 110):
 2388                 cmd = CONS_SETKBD;
 2389                 break;
 2390         default:
 2391                 goto skip_thunk;
 2392         }
 2393         ival = IOCPARM_IVAL(data);
 2394         data = (caddr_t)&ival;
 2395 skip_thunk:
 2396 #endif
 2397 
 2398         switch (cmd) {
 2399         case KDSETRAD:          /* set keyboard repeat & delay rates (old) */
 2400                 if (*(int *)data & ~0x7f)
 2401                         return (EINVAL);
 2402                 /* FALLTHROUGH */
 2403         case GIO_KEYMAP:
 2404         case PIO_KEYMAP:
 2405         case GIO_DEADKEYMAP:
 2406         case PIO_DEADKEYMAP:
 2407         case GETFKEY:
 2408         case SETFKEY:
 2409         case KDGKBINFO:
 2410         case KDGKBTYPE:
 2411         case KDGETREPEAT:       /* get keyboard repeat & delay rates */
 2412         case KDSETREPEAT:       /* set keyboard repeat & delay rates (new) */
 2413         case KBADDKBD:          /* add keyboard to mux */
 2414         case KBRELKBD: {        /* release keyboard from mux */
 2415                 error = 0;
 2416 
 2417                 mtx_lock(&Giant);
 2418                 if ((kbd = vd->vd_keyboard) != NULL)
 2419                         error = kbdd_ioctl(kbd, cmd, data);
 2420                 mtx_unlock(&Giant);
 2421                 if (error == ENOIOCTL) {
 2422                         if (cmd == KDGKBTYPE) {
 2423                                 /* always return something? XXX */
 2424                                 *(int *)data = 0;
 2425                         } else {
 2426                                 return (ENODEV);
 2427                         }
 2428                 }
 2429                 return (error);
 2430         }
 2431         case KDGKBSTATE: {      /* get keyboard state (locks) */
 2432                 error = 0;
 2433 
 2434                 if (vw == vd->vd_curwindow) {
 2435                         mtx_lock(&Giant);
 2436                         if ((kbd = vd->vd_keyboard) != NULL)
 2437                                 error = vt_save_kbd_state(vw, kbd);
 2438                         mtx_unlock(&Giant);
 2439 
 2440                         if (error != 0)
 2441                                 return (error);
 2442                 }
 2443 
 2444                 *(int *)data = vw->vw_kbdstate & LOCK_MASK;
 2445 
 2446                 return (error);
 2447         }
 2448         case KDSKBSTATE: {      /* set keyboard state (locks) */
 2449                 int state;
 2450 
 2451                 state = *(int *)data;
 2452                 if (state & ~LOCK_MASK)
 2453                         return (EINVAL);
 2454 
 2455                 vw->vw_kbdstate &= ~LOCK_MASK;
 2456                 vw->vw_kbdstate |= state;
 2457 
 2458                 error = 0;
 2459                 if (vw == vd->vd_curwindow) {
 2460                         mtx_lock(&Giant);
 2461                         if ((kbd = vd->vd_keyboard) != NULL)
 2462                                 error = vt_update_kbd_state(vw, kbd);
 2463                         mtx_unlock(&Giant);
 2464                 }
 2465 
 2466                 return (error);
 2467         }
 2468         case KDGETLED: {        /* get keyboard LED status */
 2469                 error = 0;
 2470 
 2471                 if (vw == vd->vd_curwindow) {
 2472                         mtx_lock(&Giant);
 2473                         if ((kbd = vd->vd_keyboard) != NULL)
 2474                                 error = vt_save_kbd_leds(vw, kbd);
 2475                         mtx_unlock(&Giant);
 2476 
 2477                         if (error != 0)
 2478                                 return (error);
 2479                 }
 2480 
 2481                 *(int *)data = vw->vw_kbdstate & LED_MASK;
 2482 
 2483                 return (error);
 2484         }
 2485         case KDSETLED: {        /* set keyboard LED status */
 2486                 int leds;
 2487 
 2488                 leds = *(int *)data;
 2489                 if (leds & ~LED_MASK)
 2490                         return (EINVAL);
 2491 
 2492                 vw->vw_kbdstate &= ~LED_MASK;
 2493                 vw->vw_kbdstate |= leds;
 2494 
 2495                 error = 0;
 2496                 if (vw == vd->vd_curwindow) {
 2497                         mtx_lock(&Giant);
 2498                         if ((kbd = vd->vd_keyboard) != NULL)
 2499                                 error = vt_update_kbd_leds(vw, kbd);
 2500                         mtx_unlock(&Giant);
 2501                 }
 2502 
 2503                 return (error);
 2504         }
 2505         case KDGETMODE:
 2506                 *(int *)data = (vw->vw_flags & VWF_GRAPHICS) ?
 2507                     KD_GRAPHICS : KD_TEXT;
 2508                 return (0);
 2509         case KDGKBMODE: {
 2510                 error = 0;
 2511 
 2512                 if (vw == vd->vd_curwindow) {
 2513                         mtx_lock(&Giant);
 2514                         if ((kbd = vd->vd_keyboard) != NULL)
 2515                                 error = vt_save_kbd_mode(vw, kbd);
 2516                         mtx_unlock(&Giant);
 2517 
 2518                         if (error != 0)
 2519                                 return (error);
 2520                 }
 2521 
 2522                 *(int *)data = vw->vw_kbdmode;
 2523 
 2524                 return (error);
 2525         }
 2526         case KDSKBMODE: {
 2527                 int mode;
 2528 
 2529                 mode = *(int *)data;
 2530                 switch (mode) {
 2531                 case K_XLATE:
 2532                 case K_RAW:
 2533                 case K_CODE:
 2534                         vw->vw_kbdmode = mode;
 2535 
 2536                         error = 0;
 2537                         if (vw == vd->vd_curwindow) {
 2538                                 mtx_lock(&Giant);
 2539                                 if ((kbd = vd->vd_keyboard) != NULL)
 2540                                         error = vt_update_kbd_mode(vw, kbd);
 2541                                 mtx_unlock(&Giant);
 2542                         }
 2543 
 2544                         return (error);
 2545                 default:
 2546                         return (EINVAL);
 2547                 }
 2548         }
 2549         case FBIOGTYPE:
 2550         case FBIO_GETWINORG:    /* get frame buffer window origin */
 2551         case FBIO_GETDISPSTART: /* get display start address */
 2552         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
 2553         case FBIO_BLANK:        /* blank display */
 2554         case FBIO_GETRGBOFFS:   /* get RGB offsets */
 2555                 if (vd->vd_driver->vd_fb_ioctl)
 2556                         return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td));
 2557                 break;
 2558         case CONS_BLANKTIME:
 2559                 /* XXX */
 2560                 return (0);
 2561         case CONS_HISTORY:
 2562                 if (*(int *)data < 0)
 2563                         return EINVAL;
 2564                 if (*(int *)data != vw->vw_buf.vb_history_size)
 2565                         vtbuf_sethistory_size(&vw->vw_buf, *(int *)data);
 2566                 return (0);
 2567         case CONS_CLRHIST:
 2568                 vtbuf_clearhistory(&vw->vw_buf);
 2569                 /*
 2570                  * Invalidate the entire visible window; it is not guaranteed
 2571                  * that this operation will be immediately followed by a scroll
 2572                  * event, so it would otherwise be possible for prior artifacts
 2573                  * to remain visible.
 2574                  */
 2575                 VT_LOCK(vd);
 2576                 if (vw == vd->vd_curwindow) {
 2577                         vd->vd_flags |= VDF_INVALID;
 2578                         vt_resume_flush_timer(vw, 0);
 2579                 }
 2580                 VT_UNLOCK(vd);
 2581                 return (0);
 2582         case CONS_GET:
 2583                 /* XXX */
 2584                 *(int *)data = M_CG640x480;
 2585                 return (0);
 2586         case CONS_BELLTYPE:     /* set bell type sound */
 2587                 if ((*(int *)data) & CONS_QUIET_BELL)
 2588                         vd->vd_flags |= VDF_QUIET_BELL;
 2589                 else
 2590                         vd->vd_flags &= ~VDF_QUIET_BELL;
 2591                 return (0);
 2592         case CONS_GETINFO: {
 2593                 vid_info_t *vi = (vid_info_t *)data;
 2594                 if (vi->size != sizeof(struct vid_info))
 2595                         return (EINVAL);
 2596 
 2597                 if (vw == vd->vd_curwindow) {
 2598                         mtx_lock(&Giant);
 2599                         if ((kbd = vd->vd_keyboard) != NULL)
 2600                                 vt_save_kbd_state(vw, kbd);
 2601                         mtx_unlock(&Giant);
 2602                 }
 2603 
 2604                 vi->m_num = vd->vd_curwindow->vw_number + 1;
 2605                 vi->mk_keylock = vw->vw_kbdstate & LOCK_MASK;
 2606                 /* XXX: other fields! */
 2607                 return (0);
 2608         }
 2609         case CONS_GETVERS:
 2610                 *(int *)data = 0x200;
 2611                 return (0);
 2612         case CONS_MODEINFO:
 2613                 /* XXX */
 2614                 return (0);
 2615         case CONS_MOUSECTL: {
 2616                 mouse_info_t *mouse = (mouse_info_t*)data;
 2617 
 2618                 /*
 2619                  * All the commands except MOUSE_SHOW nd MOUSE_HIDE
 2620                  * should not be applied to individual TTYs, but only to
 2621                  * consolectl.
 2622                  */
 2623                 switch (mouse->operation) {
 2624                 case MOUSE_HIDE:
 2625                         if (vd->vd_flags & VDF_MOUSECURSOR) {
 2626                                 vd->vd_flags &= ~VDF_MOUSECURSOR;
 2627 #ifndef SC_NO_CUTPASTE
 2628                                 vt_mouse_state(VT_MOUSE_HIDE);
 2629 #endif
 2630                         }
 2631                         return (0);
 2632                 case MOUSE_SHOW:
 2633                         if (!(vd->vd_flags & VDF_MOUSECURSOR)) {
 2634                                 vd->vd_flags |= VDF_MOUSECURSOR;
 2635                                 vd->vd_mx = vd->vd_width / 2;
 2636                                 vd->vd_my = vd->vd_height / 2;
 2637 #ifndef SC_NO_CUTPASTE
 2638                                 vt_mouse_state(VT_MOUSE_SHOW);
 2639 #endif
 2640                         }
 2641                         return (0);
 2642                 default:
 2643                         return (EINVAL);
 2644                 }
 2645         }
 2646         case PIO_VFONT: {
 2647                 struct vt_font *vf;
 2648 
 2649                 if (vd->vd_flags & VDF_TEXTMODE)
 2650                         return (ENOTSUP);
 2651 
 2652                 error = vtfont_load((void *)data, &vf);
 2653                 if (error != 0)
 2654                         return (error);
 2655 
 2656                 error = vt_change_font(vw, vf);
 2657                 vtfont_unref(vf);
 2658                 return (error);
 2659         }
 2660         case PIO_VFONT_DEFAULT: {
 2661                 /* Reset to default font. */
 2662                 error = vt_change_font(vw, vt_font_assigned);
 2663                 return (error);
 2664         }
 2665         case GIO_SCRNMAP: {
 2666                 scrmap_t *sm = (scrmap_t *)data;
 2667 
 2668                 /* We don't have screen maps, so return a handcrafted one. */
 2669                 for (i = 0; i < 256; i++)
 2670                         sm->scrmap[i] = i;
 2671                 return (0);
 2672         }
 2673         case KDSETMODE:
 2674                 /*
 2675                  * FIXME: This implementation is incomplete compared to
 2676                  * syscons.
 2677                  */
 2678                 switch (*(int *)data) {
 2679                 case KD_TEXT:
 2680                 case KD_TEXT1:
 2681                 case KD_PIXEL:
 2682                         vw->vw_flags &= ~VWF_GRAPHICS;
 2683                         break;
 2684                 case KD_GRAPHICS:
 2685                         vw->vw_flags |= VWF_GRAPHICS;
 2686                         break;
 2687                 }
 2688                 return (0);
 2689         case KDENABIO:          /* allow io operations */
 2690                 error = priv_check(td, PRIV_IO);
 2691                 if (error != 0)
 2692                         return (error);
 2693                 error = securelevel_gt(td->td_ucred, 0);
 2694                 if (error != 0)
 2695                         return (error);
 2696 #if defined(__i386__)
 2697                 td->td_frame->tf_eflags |= PSL_IOPL;
 2698 #elif defined(__amd64__)
 2699                 td->td_frame->tf_rflags |= PSL_IOPL;
 2700 #endif
 2701                 return (0);
 2702         case KDDISABIO:         /* disallow io operations (default) */
 2703 #if defined(__i386__)
 2704                 td->td_frame->tf_eflags &= ~PSL_IOPL;
 2705 #elif defined(__amd64__)
 2706                 td->td_frame->tf_rflags &= ~PSL_IOPL;
 2707 #endif
 2708                 return (0);
 2709         case KDMKTONE:          /* sound the bell */
 2710                 vtterm_beep(tm, *(u_int *)data);
 2711                 return (0);
 2712         case KIOCSOUND:         /* make tone (*data) hz */
 2713                 /* TODO */
 2714                 return (0);
 2715         case CONS_SETKBD:       /* set the new keyboard */
 2716                 mtx_lock(&Giant);
 2717                 error = 0;
 2718                 if (vd->vd_keyboard == NULL ||
 2719                     vd->vd_keyboard->kb_index != *(int *)data) {
 2720                         kbd = kbd_get_keyboard(*(int *)data);
 2721                         if (kbd == NULL) {
 2722                                 mtx_unlock(&Giant);
 2723                                 return (EINVAL);
 2724                         }
 2725                         i = kbd_allocate(kbd->kb_name, kbd->kb_unit,
 2726                             (void *)vd, vt_kbdevent, vd);
 2727                         if (i >= 0) {
 2728                                 if ((kbd = vd->vd_keyboard) != NULL) {
 2729                                         vt_save_kbd_state(vd->vd_curwindow, kbd);
 2730                                         kbd_release(kbd, (void *)vd);
 2731                                 }
 2732                                 kbd = vd->vd_keyboard = kbd_get_keyboard(i);
 2733 
 2734                                 vt_update_kbd_mode(vd->vd_curwindow, kbd);
 2735                                 vt_update_kbd_state(vd->vd_curwindow, kbd);
 2736                         } else {
 2737                                 error = EPERM;  /* XXX */
 2738                         }
 2739                 }
 2740                 mtx_unlock(&Giant);
 2741                 return (error);
 2742         case CONS_RELKBD:       /* release the current keyboard */
 2743                 mtx_lock(&Giant);
 2744                 error = 0;
 2745                 if ((kbd = vd->vd_keyboard) != NULL) {
 2746                         vt_save_kbd_state(vd->vd_curwindow, kbd);
 2747                         error = kbd_release(kbd, (void *)vd);
 2748                         if (error == 0) {
 2749                                 vd->vd_keyboard = NULL;
 2750                         }
 2751                 }
 2752                 mtx_unlock(&Giant);
 2753                 return (error);
 2754         case VT_ACTIVATE: {
 2755                 int win;
 2756                 win = *(int *)data - 1;
 2757                 DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME,
 2758                     VT_UNIT(vw), win);
 2759                 if ((win >= VT_MAXWINDOWS) || (win < 0))
 2760                         return (EINVAL);
 2761                 return (vt_proc_window_switch(vd->vd_windows[win]));
 2762         }
 2763         case VT_GETACTIVE:
 2764                 *(int *)data = vd->vd_curwindow->vw_number + 1;
 2765                 return (0);
 2766         case VT_GETINDEX:
 2767                 *(int *)data = vw->vw_number + 1;
 2768                 return (0);
 2769         case VT_LOCKSWITCH:
 2770                 /* TODO: Check current state, switching can be in progress. */
 2771                 if ((*(int *)data) == 0x01)
 2772                         vw->vw_flags |= VWF_VTYLOCK;
 2773                 else if ((*(int *)data) == 0x02)
 2774                         vw->vw_flags &= ~VWF_VTYLOCK;
 2775                 else
 2776                         return (EINVAL);
 2777                 return (0);
 2778         case VT_OPENQRY:
 2779                 VT_LOCK(vd);
 2780                 for (i = 0; i < VT_MAXWINDOWS; i++) {
 2781                         vw = vd->vd_windows[i];
 2782                         if (vw == NULL)
 2783                                 continue;
 2784                         if (!(vw->vw_flags & VWF_OPENED)) {
 2785                                 *(int *)data = vw->vw_number + 1;
 2786                                 VT_UNLOCK(vd);
 2787                                 return (0);
 2788                         }
 2789                 }
 2790                 VT_UNLOCK(vd);
 2791                 return (EINVAL);
 2792         case VT_WAITACTIVE: {
 2793                 unsigned int idx;
 2794 
 2795                 error = 0;
 2796 
 2797                 idx = *(unsigned int *)data;
 2798                 if (idx > VT_MAXWINDOWS)
 2799                         return (EINVAL);
 2800                 if (idx > 0)
 2801                         vw = vd->vd_windows[idx - 1];
 2802 
 2803                 VT_LOCK(vd);
 2804                 while (vd->vd_curwindow != vw && error == 0)
 2805                         error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
 2806                 VT_UNLOCK(vd);
 2807                 return (error);
 2808         }
 2809         case VT_SETMODE: {      /* set screen switcher mode */
 2810                 struct vt_mode *mode;
 2811                 struct proc *p1;
 2812 
 2813                 mode = (struct vt_mode *)data;
 2814                 DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw));
 2815                 if (vw->vw_smode.mode == VT_PROCESS) {
 2816                         p1 = pfind(vw->vw_pid);
 2817                         if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) {
 2818                                 if (p1)
 2819                                         PROC_UNLOCK(p1);
 2820                                 DPRINTF(5, "error EPERM\n");
 2821                                 return (EPERM);
 2822                         }
 2823                         if (p1)
 2824                                 PROC_UNLOCK(p1);
 2825                 }
 2826                 if (mode->mode == VT_AUTO) {
 2827                         vw->vw_smode.mode = VT_AUTO;
 2828                         vw->vw_proc = NULL;
 2829                         vw->vw_pid = 0;
 2830                         DPRINTF(5, "VT_AUTO, ");
 2831                         if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
 2832                                 cnavailable(vw->vw_terminal->consdev, TRUE);
 2833                         /* were we in the middle of the vty switching process? */
 2834                         if (finish_vt_rel(vw, TRUE, &s) == 0)
 2835                                 DPRINTF(5, "reset WAIT_REL, ");
 2836                         if (finish_vt_acq(vw) == 0)
 2837                                 DPRINTF(5, "reset WAIT_ACQ, ");
 2838                         return (0);
 2839                 } else if (mode->mode == VT_PROCESS) {
 2840                         if (!ISSIGVALID(mode->relsig) ||
 2841                             !ISSIGVALID(mode->acqsig) ||
 2842                             !ISSIGVALID(mode->frsig)) {
 2843                                 DPRINTF(5, "error EINVAL\n");
 2844                                 return (EINVAL);
 2845                         }
 2846                         DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid);
 2847                         bcopy(data, &vw->vw_smode, sizeof(struct vt_mode));
 2848                         vw->vw_proc = td->td_proc;
 2849                         vw->vw_pid = vw->vw_proc->p_pid;
 2850                         if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
 2851                                 cnavailable(vw->vw_terminal->consdev, FALSE);
 2852                 } else {
 2853                         DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n",
 2854                             mode->mode);
 2855                         return (EINVAL);
 2856                 }
 2857                 DPRINTF(5, "\n");
 2858                 return (0);
 2859         }
 2860         case VT_GETMODE:        /* get screen switcher mode */
 2861                 bcopy(&vw->vw_smode, data, sizeof(struct vt_mode));
 2862                 return (0);
 2863 
 2864         case VT_RELDISP:        /* screen switcher ioctl */
 2865                 /*
 2866                  * This must be the current vty which is in the VT_PROCESS
 2867                  * switching mode...
 2868                  */
 2869                 if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode !=
 2870                     VT_PROCESS)) {
 2871                         return (EINVAL);
 2872                 }
 2873                 /* ...and this process is controlling it. */
 2874                 if (vw->vw_proc != td->td_proc) {
 2875                         return (EPERM);
 2876                 }
 2877                 error = EINVAL;
 2878                 switch(*(int *)data) {
 2879                 case VT_FALSE:  /* user refuses to release screen, abort */
 2880                         if ((error = finish_vt_rel(vw, FALSE, &s)) == 0)
 2881                                 DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n",
 2882                                     SC_DRIVER_NAME, VT_UNIT(vw));
 2883                         break;
 2884                 case VT_TRUE:   /* user has released screen, go on */
 2885                         /* finish_vt_rel(..., TRUE, ...) should not be locked */
 2886                         if (vw->vw_flags & VWF_SWWAIT_REL) {
 2887                                 if ((error = finish_vt_rel(vw, TRUE, &s)) == 0)
 2888                                         DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n",
 2889                                             SC_DRIVER_NAME, VT_UNIT(vw));
 2890                         } else {
 2891                                 error = EINVAL;
 2892                         }
 2893                         return (error);
 2894                 case VT_ACKACQ: /* acquire acknowledged, switch completed */
 2895                         if ((error = finish_vt_acq(vw)) == 0)
 2896                                 DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n",
 2897                                     SC_DRIVER_NAME, VT_UNIT(vw));
 2898                         break;
 2899                 default:
 2900                         break;
 2901                 }
 2902                 return (error);
 2903         }
 2904 
 2905         return (ENOIOCTL);
 2906 }
 2907 
 2908 static struct vt_window *
 2909 vt_allocate_window(struct vt_device *vd, unsigned int window)
 2910 {
 2911         struct vt_window *vw;
 2912         struct terminal *tm;
 2913         term_pos_t size;
 2914         struct winsize wsz;
 2915 
 2916         vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO);
 2917         vw->vw_device = vd;
 2918         vw->vw_number = window;
 2919         vw->vw_kbdmode = K_XLATE;
 2920 
 2921         if ((vd->vd_flags & VDF_TEXTMODE) == 0) {
 2922                 vw->vw_font = vtfont_ref(vt_font_assigned);
 2923                 vt_compute_drawable_area(vw);
 2924         }
 2925 
 2926         vt_termsize(vd, vw->vw_font, &size);
 2927         vt_winsize(vd, vw->vw_font, &wsz);
 2928         tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw);
 2929         vw->vw_buf.vb_terminal = tm;    /* must be set before vtbuf_init() */
 2930         vtbuf_init(&vw->vw_buf, &size);
 2931 
 2932         terminal_set_winsize(tm, &wsz);
 2933         vd->vd_windows[window] = vw;
 2934         TIMEOUT_TASK_INIT(taskqueue_thread, &vw->vw_timeout_task_dead, 0, &vt_switch_timer, vw);
 2935 
 2936         return (vw);
 2937 }
 2938 
 2939 void
 2940 vt_upgrade(struct vt_device *vd)
 2941 {
 2942         struct vt_window *vw;
 2943         unsigned int i;
 2944         int register_handlers;
 2945 
 2946         if (!vty_enabled(VTY_VT))
 2947                 return;
 2948         if (main_vd->vd_driver == NULL)
 2949                 return;
 2950 
 2951         for (i = 0; i < VT_MAXWINDOWS; i++) {
 2952                 vw = vd->vd_windows[i];
 2953                 if (vw == NULL) {
 2954                         /* New window. */
 2955                         vw = vt_allocate_window(vd, i);
 2956                 }
 2957                 if (!(vw->vw_flags & VWF_READY)) {
 2958                         TIMEOUT_TASK_INIT(taskqueue_thread, &vw->vw_timeout_task_dead, 0, &vt_switch_timer, vw);
 2959                         terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw));
 2960                         vw->vw_flags |= VWF_READY;
 2961                         if (vw->vw_flags & VWF_CONSOLE) {
 2962                                 /* For existing console window. */
 2963                                 EVENTHANDLER_REGISTER(shutdown_pre_sync,
 2964                                     vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT);
 2965                         }
 2966                 }
 2967         }
 2968         VT_LOCK(vd);
 2969         if (vd->vd_curwindow == NULL)
 2970                 vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW];
 2971 
 2972         register_handlers = 0;
 2973         if (!(vd->vd_flags & VDF_ASYNC)) {
 2974                 /* Attach keyboard. */
 2975                 vt_allocate_keyboard(vd);
 2976 
 2977                 /* Init 25 Hz timer. */
 2978                 callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0);
 2979 
 2980                 /*
 2981                  * Start timer when everything ready.
 2982                  * Note that the operations here are purposefully ordered.
 2983                  * We need to ensure vd_timer_armed is non-zero before we set
 2984                  * the VDF_ASYNC flag. That prevents this function from
 2985                  * racing with vt_resume_flush_timer() to update the
 2986                  * callout structure.
 2987                  */
 2988                 atomic_add_acq_int(&vd->vd_timer_armed, 1);
 2989                 vd->vd_flags |= VDF_ASYNC;
 2990                 callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd);
 2991                 register_handlers = 1;
 2992         }
 2993 
 2994         VT_UNLOCK(vd);
 2995 
 2996         /* Refill settings with new sizes. */
 2997         vt_resize(vd);
 2998 
 2999         if (register_handlers) {
 3000                 /* Register suspend/resume handlers. */
 3001                 EVENTHANDLER_REGISTER(power_suspend_early, vt_suspend_handler,
 3002                     vd, EVENTHANDLER_PRI_ANY);
 3003                 EVENTHANDLER_REGISTER(power_resume, vt_resume_handler, vd,
 3004                     EVENTHANDLER_PRI_ANY);
 3005         }
 3006 }
 3007 
 3008 static void
 3009 vt_resize(struct vt_device *vd)
 3010 {
 3011         struct vt_window *vw;
 3012         int i;
 3013 
 3014         for (i = 0; i < VT_MAXWINDOWS; i++) {
 3015                 vw = vd->vd_windows[i];
 3016                 VT_LOCK(vd);
 3017                 /* Assign default font to window, if not textmode. */
 3018                 if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL)
 3019                         vw->vw_font = vtfont_ref(vt_font_assigned);
 3020                 VT_UNLOCK(vd);
 3021 
 3022                 /* Resize terminal windows */
 3023                 while (vt_change_font(vw, vw->vw_font) == EBUSY) {
 3024                         DPRINTF(100, "%s: vt_change_font() is busy, "
 3025                             "window %d\n", __func__, i);
 3026                 }
 3027         }
 3028 }
 3029 
 3030 static void
 3031 vt_replace_backend(const struct vt_driver *drv, void *softc)
 3032 {
 3033         struct vt_device *vd;
 3034 
 3035         vd = main_vd;
 3036 
 3037         if (vd->vd_flags & VDF_ASYNC) {
 3038                 /* Stop vt_flush periodic task. */
 3039                 VT_LOCK(vd);
 3040                 vt_suspend_flush_timer(vd);
 3041                 VT_UNLOCK(vd);
 3042                 /*
 3043                  * Mute current terminal until we done. vt_change_font (called
 3044                  * from vt_resize) will unmute it.
 3045                  */
 3046                 terminal_mute(vd->vd_curwindow->vw_terminal, 1);
 3047         }
 3048 
 3049         /*
 3050          * Reset VDF_TEXTMODE flag, driver who require that flag (vt_vga) will
 3051          * set it.
 3052          */
 3053         VT_LOCK(vd);
 3054         vd->vd_flags &= ~VDF_TEXTMODE;
 3055 
 3056         if (drv != NULL) {
 3057                 /*
 3058                  * We want to upgrade from the current driver to the
 3059                  * given driver.
 3060                  */
 3061 
 3062                 vd->vd_prev_driver = vd->vd_driver;
 3063                 vd->vd_prev_softc = vd->vd_softc;
 3064                 vd->vd_driver = drv;
 3065                 vd->vd_softc = softc;
 3066 
 3067                 vd->vd_driver->vd_init(vd);
 3068         } else if (vd->vd_prev_driver != NULL && vd->vd_prev_softc != NULL) {
 3069                 /*
 3070                  * No driver given: we want to downgrade to the previous
 3071                  * driver.
 3072                  */
 3073                 const struct vt_driver *old_drv;
 3074                 void *old_softc;
 3075 
 3076                 old_drv = vd->vd_driver;
 3077                 old_softc = vd->vd_softc;
 3078 
 3079                 vd->vd_driver = vd->vd_prev_driver;
 3080                 vd->vd_softc = vd->vd_prev_softc;
 3081                 vd->vd_prev_driver = NULL;
 3082                 vd->vd_prev_softc = NULL;
 3083 
 3084                 vd->vd_flags |= VDF_DOWNGRADE;
 3085 
 3086                 vd->vd_driver->vd_init(vd);
 3087 
 3088                 if (old_drv->vd_fini)
 3089                         old_drv->vd_fini(vd, old_softc);
 3090 
 3091                 vd->vd_flags &= ~VDF_DOWNGRADE;
 3092         }
 3093 
 3094         VT_UNLOCK(vd);
 3095 
 3096         /* Update windows sizes and initialize last items. */
 3097         vt_upgrade(vd);
 3098 
 3099 #ifdef DEV_SPLASH
 3100         if (vd->vd_flags & VDF_SPLASH)
 3101                 vtterm_splash(vd);
 3102 #endif
 3103 
 3104         if (vd->vd_flags & VDF_ASYNC) {
 3105                 /* Allow to put chars now. */
 3106                 terminal_mute(vd->vd_curwindow->vw_terminal, 0);
 3107                 /* Rerun timer for screen updates. */
 3108                 vt_resume_flush_timer(vd->vd_curwindow, 0);
 3109         }
 3110 
 3111         /*
 3112          * Register as console. If it already registered, cnadd() will ignore
 3113          * it.
 3114          */
 3115         termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal);
 3116 }
 3117 
 3118 static void
 3119 vt_suspend_handler(void *priv)
 3120 {
 3121         struct vt_device *vd;
 3122 
 3123         vd = priv;
 3124         vd->vd_flags |= VDF_SUSPENDED;
 3125         if (vd->vd_driver != NULL && vd->vd_driver->vd_suspend != NULL)
 3126                 vd->vd_driver->vd_suspend(vd);
 3127 }
 3128 
 3129 static void
 3130 vt_resume_handler(void *priv)
 3131 {
 3132         struct vt_device *vd;
 3133 
 3134         vd = priv;
 3135         if (vd->vd_driver != NULL && vd->vd_driver->vd_resume != NULL)
 3136                 vd->vd_driver->vd_resume(vd);
 3137         vd->vd_flags &= ~VDF_SUSPENDED;
 3138 }
 3139 
 3140 int
 3141 vt_allocate(const struct vt_driver *drv, void *softc)
 3142 {
 3143 
 3144         if (!vty_enabled(VTY_VT))
 3145                 return (EINVAL);
 3146 
 3147         if (main_vd->vd_driver == NULL) {
 3148                 main_vd->vd_driver = drv;
 3149                 printf("VT: initialize with new VT driver \"%s\".\n",
 3150                     drv->vd_name);
 3151         } else {
 3152                 /*
 3153                  * Check if have rights to replace current driver. For example:
 3154                  * it is bad idea to replace KMS driver with generic VGA one.
 3155                  */
 3156                 if (drv->vd_priority <= main_vd->vd_driver->vd_priority) {
 3157                         printf("VT: Driver priority %d too low. Current %d\n ",
 3158                             drv->vd_priority, main_vd->vd_driver->vd_priority);
 3159                         return (EEXIST);
 3160                 }
 3161                 printf("VT: Replacing driver \"%s\" with new \"%s\".\n",
 3162                     main_vd->vd_driver->vd_name, drv->vd_name);
 3163         }
 3164 
 3165         vt_replace_backend(drv, softc);
 3166 
 3167         return (0);
 3168 }
 3169 
 3170 int
 3171 vt_deallocate(const struct vt_driver *drv, void *softc)
 3172 {
 3173 
 3174         if (!vty_enabled(VTY_VT))
 3175                 return (EINVAL);
 3176 
 3177         if (main_vd->vd_prev_driver == NULL ||
 3178             main_vd->vd_driver != drv ||
 3179             main_vd->vd_softc != softc)
 3180                 return (EPERM);
 3181 
 3182         printf("VT: Switching back from \"%s\" to \"%s\".\n",
 3183             main_vd->vd_driver->vd_name, main_vd->vd_prev_driver->vd_name);
 3184 
 3185         vt_replace_backend(NULL, NULL);
 3186 
 3187         return (0);
 3188 }
 3189 
 3190 void
 3191 vt_suspend(struct vt_device *vd)
 3192 {
 3193         int error;
 3194 
 3195         if (vt_suspendswitch == 0)
 3196                 return;
 3197         /* Save current window. */
 3198         vd->vd_savedwindow = vd->vd_curwindow;
 3199         /* Ask holding process to free window and switch to console window */
 3200         vt_proc_window_switch(vd->vd_windows[VT_CONSWINDOW]);
 3201 
 3202         /* Wait for the window switch to complete. */
 3203         error = 0;
 3204         VT_LOCK(vd);
 3205         while (vd->vd_curwindow != vd->vd_windows[VT_CONSWINDOW] && error == 0)
 3206                 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
 3207         VT_UNLOCK(vd);
 3208 }
 3209 
 3210 void
 3211 vt_resume(struct vt_device *vd)
 3212 {
 3213 
 3214         if (vt_suspendswitch == 0)
 3215                 return;
 3216         /* Switch back to saved window, if any */
 3217         vt_proc_window_switch(vd->vd_savedwindow);
 3218         vd->vd_savedwindow = NULL;
 3219 }

Cache object: bd37a9644154e40b3e203255f04a0ba8


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