vt_core.c revision 271128
1139823Simp/*- 263670Snsayer * Copyright (c) 2009, 2013 The FreeBSD Foundation 363670Snsayer * All rights reserved. 463670Snsayer * 563670Snsayer * This software was developed by Ed Schouten under sponsorship from the 663670Snsayer * FreeBSD Foundation. 763670Snsayer * 863670Snsayer * Portions of this software were developed by Oleksandr Rybalko 963670Snsayer * under sponsorship from the FreeBSD Foundation. 1063670Snsayer * 1163670Snsayer * Redistribution and use in source and binary forms, with or without 1263670Snsayer * modification, are permitted provided that the following conditions 1363670Snsayer * are met: 1463670Snsayer * 1. Redistributions of source code must retain the above copyright 1563670Snsayer * notice, this list of conditions and the following disclaimer. 1663670Snsayer * 2. Redistributions in binary form must reproduce the above copyright 1763670Snsayer * notice, this list of conditions and the following disclaimer in the 1863670Snsayer * documentation and/or other materials provided with the distribution. 1963670Snsayer * 2063670Snsayer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2163670Snsayer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2263670Snsayer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2363670Snsayer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2463670Snsayer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2563670Snsayer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2663670Snsayer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2763670Snsayer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2863670Snsayer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2963670Snsayer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3063670Snsayer * SUCH DAMAGE. 3163670Snsayer */ 3263670Snsayer 3363670Snsayer#include <sys/cdefs.h> 3463670Snsayer__FBSDID("$FreeBSD: stable/10/sys/dev/vt/vt_core.c 271128 2014-09-04 20:18:08Z emaste $"); 3563803Snsayer 3663670Snsayer#include "opt_compat.h" 3763670Snsayer 38162711Sru#include <sys/param.h> 3963670Snsayer#include <sys/consio.h> 4063670Snsayer#include <sys/eventhandler.h> 4163670Snsayer#include <sys/fbio.h> 4263670Snsayer#include <sys/kbio.h> 43139207Sphk#include <sys/kdb.h> 4463670Snsayer#include <sys/kernel.h> 45236724Strociny#include <sys/lock.h> 4663670Snsayer#include <sys/malloc.h> 4763670Snsayer#include <sys/mutex.h> 4863670Snsayer#include <sys/priv.h> 49129880Sphk#include <sys/proc.h> 5063670Snsayer#include <sys/reboot.h> 51164033Srwatson#include <sys/systm.h> 5263670Snsayer#include <sys/terminal.h> 53139207Sphk 5463670Snsayer#include <dev/kbd/kbdreg.h> 5563670Snsayer#include <dev/vt/vt.h> 5663670Snsayer 5763670Snsayer#if defined(__i386__) || defined(__amd64__) 5863670Snsayer#include <machine/psl.h> 5963670Snsayer#include <machine/frame.h> 6063670Snsayer#endif 6183043Sbrooks 6263670Snsayerstatic tc_bell_t vtterm_bell; 6363670Snsayerstatic tc_cursor_t vtterm_cursor; 6463670Snsayerstatic tc_putchar_t vtterm_putchar; 6563670Snsayerstatic tc_fill_t vtterm_fill; 66166497Sbmsstatic tc_copy_t vtterm_copy; 67152315Srustatic tc_param_t vtterm_param; 68238183Semastestatic tc_done_t vtterm_done; 69236725Strociny 7063670Snsayerstatic tc_cnprobe_t vtterm_cnprobe; 71236724Strocinystatic tc_cngetc_t vtterm_cngetc; 7263670Snsayer 7363670Snsayerstatic tc_opened_t vtterm_opened; 7463670Snsayerstatic tc_ioctl_t vtterm_ioctl; 7563670Snsayerstatic tc_mmap_t vtterm_mmap; 7663670Snsayer 7763670Snsayerconst struct terminal_class vt_termclass = { 7863670Snsayer .tc_bell = vtterm_bell, 7963670Snsayer .tc_cursor = vtterm_cursor, 8063670Snsayer .tc_putchar = vtterm_putchar, 8163670Snsayer .tc_fill = vtterm_fill, 8263670Snsayer .tc_copy = vtterm_copy, 8363670Snsayer .tc_param = vtterm_param, 8483043Sbrooks .tc_done = vtterm_done, 85126077Sphk 8663670Snsayer .tc_cnprobe = vtterm_cnprobe, 8763670Snsayer .tc_cngetc = vtterm_cngetc, 88111742Sdes 8963670Snsayer .tc_opened = vtterm_opened, 9063670Snsayer .tc_ioctl = vtterm_ioctl, 91148868Srwatson .tc_mmap = vtterm_mmap, 92148868Srwatson}; 93130585Sphk 9463670Snsayer/* 9563670Snsayer * Use a constant timer of 25 Hz to redraw the screen. 9693084Sbde * 9793084Sbde * XXX: In theory we should only fire up the timer when there is really 9893084Sbde * activity. Unfortunately we cannot always start timers. We really 9963670Snsayer * don't want to process kernel messages synchronously, because it 100166497Sbms * really slows down the system. 101166497Sbms */ 102166497Sbms#define VT_TIMERFREQ 25 103166497Sbms 104166497Sbms/* Bell pitch/duration. */ 105166497Sbms#define VT_BELLDURATION ((5 * hz + 99) / 100) 106166497Sbms#define VT_BELLPITCH 800 107166497Sbms 10863670Snsayer#define VT_LOCK(vd) mtx_lock(&(vd)->vd_lock) 10963670Snsayer#define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) 11063670Snsayer 11163670Snsayer#define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \ 11263670Snsayer (vw)->vw_number) 11363670Snsayer 11463670Snsayerstatic SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "vt(9) parameters"); 115156783SemaxVT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)"); 11663670SnsayerVT_SYSCTL_INT(debug, 0, "vt(9) debug level"); 117156783SemaxVT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); 118156783SemaxVT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend"); 119156783Semax 120156783Semaxstatic struct vt_device vt_consdev; 121156783Semaxstatic unsigned int vt_unit = 0; 122156783Semaxstatic MALLOC_DEFINE(M_VT, "vt", "vt device"); 123156783Semaxstruct vt_device *main_vd = &vt_consdev; 124156783Semax 125156783Semax/* Boot logo. */ 126156783Semaxextern unsigned int vt_logo_width; 127156783Semaxextern unsigned int vt_logo_height; 128156783Semaxextern unsigned int vt_logo_depth; 129156783Semaxextern unsigned char vt_logo_image[]; 130156783Semax 131156783Semax/* Font. */ 132156783Semaxextern struct vt_font vt_font_default; 133156783Semax#ifndef SC_NO_CUTPASTE 134156783Semaxextern struct vt_mouse_cursor vt_default_mouse_pointer; 135156783Semax#endif 13663670Snsayer 137126080Sphkstatic int signal_vt_rel(struct vt_window *); 138226500Sedstatic int signal_vt_acq(struct vt_window *); 139111815Sphkstatic int finish_vt_rel(struct vt_window *, int, int *); 140111815Sphkstatic int finish_vt_acq(struct vt_window *); 141111815Sphkstatic int vt_window_switch(struct vt_window *); 142111815Sphkstatic int vt_late_window_switch(struct vt_window *); 143111815Sphkstatic int vt_proc_alive(struct vt_window *); 144111815Sphkstatic void vt_resize(struct vt_device *); 145111815Sphkstatic void vt_update_static(void *); 146156783Semax 14763670SnsayerSET_DECLARE(vt_drv_set, struct vt_driver); 14863670Snsayer 149127003Srwatson#define _VTDEFH MAX(100, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)) 150127003Srwatson#define _VTDEFW MAX(200, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)) 151127003Srwatson 152127003Srwatsonstatic struct terminal vt_consterm; 153127003Srwatsonstatic struct vt_window vt_conswindow; 154127003Srwatsonstatic struct vt_device vt_consdev = { 15583043Sbrooks .vd_driver = NULL, 156167713Sbms .vd_softc = NULL, 157167713Sbms .vd_flags = VDF_INVALID, 158166497Sbms .vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, }, 15983043Sbrooks .vd_curwindow = &vt_conswindow, 160126077Sphk .vd_markedwin = NULL, 16163670Snsayer .vd_kbstate = 0, 16263670Snsayer 16363670Snsayer#ifndef SC_NO_CUTPASTE 16463670Snsayer .vd_mcursor = &vt_default_mouse_pointer, 165144979Smdodd .vd_mcursor_fg = TC_WHITE, 166144979Smdodd .vd_mcursor_bg = TC_BLACK, 167227309Sed#endif 168144979Smdodd}; 169144979Smdoddstatic term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)]; 170144979Smdoddstatic term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE]; 171167713Sbmsstatic struct vt_window vt_conswindow = { 172167713Sbms .vw_number = VT_CONSWINDOW, 173166497Sbms .vw_flags = VWF_CONSOLE, 174166497Sbms .vw_buf = { 175144979Smdodd .vb_buffer = &vt_constextbuf[0], 176144979Smdodd .vb_rows = &vt_constextbufrows[0], 177166497Sbms .vb_history_size = VBF_DEFAULT_HISTORY_SIZE, 178166497Sbms .vb_curroffset = 0, 17963670Snsayer .vb_roffset = 0, 18063670Snsayer .vb_flags = VBF_STATIC, 181166497Sbms .vb_mark_start = {.tp_row = 0, .tp_col = 0,}, 182166497Sbms .vb_mark_end = {.tp_row = 0, .tp_col = 0,}, 183166497Sbms .vb_scr_size = { 184166497Sbms .tp_row = _VTDEFH, 185166497Sbms .tp_col = _VTDEFW, 186166497Sbms }, 187166497Sbms }, 188166497Sbms .vw_device = &vt_consdev, 189166497Sbms .vw_terminal = &vt_consterm, 190166497Sbms .vw_kbdmode = K_XLATE, 191166497Sbms}; 192166497Sbmsstatic struct terminal vt_consterm = { 193166497Sbms .tm_class = &vt_termclass, 194166497Sbms .tm_softc = &vt_conswindow, 195166497Sbms .tm_flags = TF_CONS, 196183381Sed}; 197166497Sbmsstatic struct consdev vt_consterm_consdev = { 198166497Sbms .cn_ops = &termcn_cnops, 199166497Sbms .cn_arg = &vt_consterm, 200166497Sbms .cn_name = "ttyv0", 201166497Sbms}; 202166497Sbms 203166497Sbms/* Add to set of consoles. */ 204166497SbmsDATA_SET(cons_set, vt_consterm_consdev); 205166497Sbms 206166497Sbms/* 207166497Sbms * Right after kmem is done to allow early drivers to use locking and allocate 208166497Sbms * memory. 209166497Sbms */ 210166497SbmsSYSINIT(vt_update_static, SI_SUB_KMEM, SI_ORDER_ANY, vt_update_static, 211166497Sbms &vt_consdev); 212166497Sbms/* Delay until all devices attached, to not waste time. */ 213166497SbmsSYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade, 214166497Sbms &vt_consdev); 215166497Sbms 216236724Strociny/* Initialize locks/mem depended members. */ 217240938Semastestatic void 218225177Sattiliovt_update_static(void *dummy) 219166497Sbms{ 220166497Sbms 221227459Sbrooks if (!vty_enabled(VTY_VT)) 222166497Sbms return; 223166497Sbms if (main_vd->vd_driver != NULL) 224166497Sbms printf("VT: running with driver \"%s\".\n", 225236724Strociny main_vd->vd_driver->vd_name); 226166497Sbms else 227166497Sbms printf("VT: init without driver.\n"); 228166497Sbms 229166497Sbms mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); 230166497Sbms cv_init(&main_vd->vd_winswitch, "vtwswt"); 231166497Sbms} 232166497Sbms 233166497Sbmsstatic void 234166497Sbmsvt_schedule_flush(struct vt_device *vd, int ms) 235166497Sbms{ 236166497Sbms 237166497Sbms if (ms <= 0) 238166497Sbms /* Default to initial value. */ 239166497Sbms ms = 1000 / VT_TIMERFREQ; 240166497Sbms 241166497Sbms callout_schedule(&vd->vd_timer, hz / (1000 / ms)); 242166497Sbms} 243166497Sbms 244166497Sbmsstatic void 245166497Sbmsvt_resume_flush_timer(struct vt_device *vd, int ms) 24663670Snsayer{ 24763670Snsayer 24863670Snsayer if (!(vd->vd_flags & VDF_ASYNC) || 24963670Snsayer !atomic_cmpset_int(&vd->vd_timer_armed, 0, 1)) 25063670Snsayer return; 25163670Snsayer 252156783Semax vt_schedule_flush(vd, ms); 25363670Snsayer} 25483043Sbrooks 25583043Sbrooksstatic void 25683043Sbrooksvt_suspend_flush_timer(struct vt_device *vd) 25763670Snsayer{ 25863670Snsayer 25963670Snsayer if (!(vd->vd_flags & VDF_ASYNC) || 26063670Snsayer !atomic_cmpset_int(&vd->vd_timer_armed, 1, 0)) 26183043Sbrooks return; 26283043Sbrooks 263127003Srwatson callout_drain(&vd->vd_timer); 26483043Sbrooks} 26583043Sbrooks 266126845Sphkstatic void 26771602Sphkvt_switch_timer(void *arg) 268127003Srwatson{ 269127170Srwatson 270127003Srwatson vt_late_window_switch((struct vt_window *)arg); 271126077Sphk} 272127003Srwatson 273166497Sbmsstatic int 274166497Sbmsvt_window_preswitch(struct vt_window *vw, struct vt_window *curvw) 27583043Sbrooks{ 27663670Snsayer 27783043Sbrooks DPRINTF(40, "%s\n", __func__); 278127003Srwatson curvw->vw_switch_to = vw; 279127003Srwatson /* Set timer to allow switch in case when process hang. */ 280127003Srwatson callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer, 281127003Srwatson vt_switch_timer, (void *)vw); 282127003Srwatson /* Notify process about vt switch attempt. */ 283127003Srwatson DPRINTF(30, "%s: Notify process.\n", __func__); 284127003Srwatson signal_vt_rel(curvw); 285127098Srwatson 286127003Srwatson return (0); 287127098Srwatson} 288127003Srwatson 28983043Sbrooksstatic int 290127003Srwatsonvt_window_postswitch(struct vt_window *vw) 291127098Srwatson{ 292127003Srwatson 293127003Srwatson signal_vt_acq(vw); 29483043Sbrooks return (0); 29571602Sphk} 296166497Sbms 297166497Sbms/* vt_late_window_switch will done VT switching for regular case. */ 298204464Skibstatic int 29963670Snsayervt_late_window_switch(struct vt_window *vw) 300127003Srwatson{ 30183043Sbrooks int ret; 30283043Sbrooks 303127003Srwatson callout_stop(&vw->vw_proc_dead_timer); 30483043Sbrooks 305147256Sbrooks ret = vt_window_switch(vw); 30683043Sbrooks if (ret) 307121816Sbrooks return (ret); 30883043Sbrooks 309166497Sbms /* Notify owner process about terminal availability. */ 310127003Srwatson if (vw->vw_smode.mode == VT_PROCESS) { 31183043Sbrooks ret = vt_window_postswitch(vw); 312127003Srwatson } 313126077Sphk return (ret); 31463670Snsayer} 315135354Srwatson 316135354Srwatson/* Switch window. */ 31783043Sbrooksstatic int 31863670Snsayervt_proc_window_switch(struct vt_window *vw) 31963670Snsayer{ 32063670Snsayer struct vt_window *curvw; 32163670Snsayer struct vt_device *vd; 32263670Snsayer int ret; 32363670Snsayer 32463670Snsayer vd = vw->vw_device; 32563670Snsayer curvw = vd->vd_curwindow; 32663670Snsayer 32763670Snsayer if (curvw->vw_flags & VWF_VTYLOCK) 32871602Sphk return (EBUSY); 32971602Sphk 33071602Sphk /* Ask current process permitions to switch away. */ 33171602Sphk if (curvw->vw_smode.mode == VT_PROCESS) { 33271602Sphk DPRINTF(30, "%s: VT_PROCESS ", __func__); 333156783Semax if (vt_proc_alive(curvw) == FALSE) { 33471602Sphk DPRINTF(30, "Dead. Cleaning."); 335166497Sbms /* Dead */ 336166497Sbms } else { 337166438Sbms DPRINTF(30, "%s: Signaling process.\n", __func__); 33871602Sphk /* Alive, try to ask him. */ 339130640Sphk ret = vt_window_preswitch(vw, curvw); 34071602Sphk /* Wait for process answer or timeout. */ 34171602Sphk return (ret); 342166514Sbms } 343166514Sbms DPRINTF(30, "\n"); 344166497Sbms } 345166497Sbms 346166497Sbms ret = vt_late_window_switch(vw); 347166497Sbms return (ret); 348126077Sphk} 349166497Sbms 350166497Sbms/* Switch window ignoring process locking. */ 351126077Sphkstatic int 352126077Sphkvt_window_switch(struct vt_window *vw) 353126077Sphk{ 354126077Sphk struct vt_device *vd = vw->vw_device; 355126077Sphk struct vt_window *curvw = vd->vd_curwindow; 356166497Sbms keyboard_t *kbd; 357166497Sbms 358126077Sphk VT_LOCK(vd); 359166497Sbms if (curvw == vw) { 360166497Sbms /* Nothing to do. */ 361166497Sbms VT_UNLOCK(vd); 36283043Sbrooks return (0); 36371602Sphk } 364166497Sbms if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 365166497Sbms VT_UNLOCK(vd); 366166497Sbms return (EINVAL); 367236724Strociny } 368126077Sphk 369126077Sphk vt_suspend_flush_timer(vd); 370126077Sphk 371166497Sbms vd->vd_curwindow = vw; 372166497Sbms vd->vd_flags |= VDF_INVALID; 373166497Sbms cv_broadcast(&vd->vd_winswitch); 374166497Sbms VT_UNLOCK(vd); 375166497Sbms 376166497Sbms if (vd->vd_driver->vd_postswitch) 377166497Sbms vd->vd_driver->vd_postswitch(vd); 378166497Sbms 379166497Sbms vt_resume_flush_timer(vd, 0); 380166497Sbms 381204464Skib /* Restore per-window keyboard mode. */ 382204464Skib mtx_lock(&Giant); 38371602Sphk kbd = kbd_get_keyboard(vd->vd_keyboard); 384166497Sbms if (kbd != NULL) { 385166497Sbms kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode); 386236724Strociny } 38771602Sphk mtx_unlock(&Giant); 38871602Sphk DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number); 38971602Sphk 39071602Sphk return (0); 39163670Snsayer} 39263670Snsayer 39363670Snsayerstatic inline void 39463670Snsayervt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size) 39563670Snsayer{ 396156783Semax 39763670Snsayer size->tp_row = vd->vd_height; 39863670Snsayer size->tp_col = vd->vd_width; 39963670Snsayer if (vf != NULL) { 40063670Snsayer size->tp_row /= vf->vf_height; 401178221Semax size->tp_col /= vf->vf_width; 402213028Sjhb } 40363670Snsayer} 404147256Sbrooks 40563670Snsayerstatic inline void 406126077Sphkvt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size) 407126077Sphk{ 40863670Snsayer 409184205Sdes size->ws_row = size->ws_ypixel = vd->vd_height; 410127098Srwatson size->ws_col = size->ws_xpixel = vd->vd_width; 411127003Srwatson if (vf != NULL) { 41283043Sbrooks size->ws_row /= vf->vf_height; 413127003Srwatson size->ws_col /= vf->vf_width; 41463670Snsayer } 415126796Sphk} 41683043Sbrooks 41763670Snsayerstatic inline void 418126796Sphkvt_compute_drawable_area(struct vt_window *vw) 41963670Snsayer{ 42063803Snsayer struct vt_device *vd; 42183043Sbrooks struct vt_font *vf; 42263670Snsayer 42363670Snsayer if (vw->vw_font == NULL) 424126796Sphk return; 425126796Sphk 426183397Sed vd = vw->vw_device; 42783043Sbrooks vf = vw->vw_font; 42863670Snsayer 42963670Snsayer /* 430178221Semax * Compute the drawable area, so that the text is centered on 431147256Sbrooks * the screen. 432178221Semax */ 433147256Sbrooks 43463670Snsayer vw->vw_draw_area.tr_begin.tp_col = (vd->vd_width % vf->vf_width) / 2; 435111742Sdes vw->vw_draw_area.tr_begin.tp_row = (vd->vd_height % vf->vf_height) / 2; 436147256Sbrooks vw->vw_draw_area.tr_end.tp_col = vw->vw_draw_area.tr_begin.tp_col + 437147256Sbrooks vd->vd_width / vf->vf_width * vf->vf_width; 438147256Sbrooks vw->vw_draw_area.tr_end.tp_row = vw->vw_draw_area.tr_begin.tp_row + 43963670Snsayer vd->vd_height / vf->vf_height * vf->vf_height; 440121816Sbrooks} 44163670Snsayer 44263670Snsayerstatic void 44363670Snsayervt_scroll(struct vt_window *vw, int offset, int whence) 44463670Snsayer{ 44563670Snsayer int diff; 446213028Sjhb term_pos_t size; 447205222Sqingli 448205222Sqingli if ((vw->vw_flags & VWF_SCROLL) == 0) 44963670Snsayer return; 45083043Sbrooks 451126077Sphk vt_termsize(vw->vw_device, vw->vw_font, &size); 45283043Sbrooks 453147256Sbrooks diff = vthistory_seek(&vw->vw_buf, offset, whence); 45463670Snsayer /* 455127098Srwatson * Offset changed, please update Nth lines on screen. 45663803Snsayer * +N - Nth lines at top; 457127098Srwatson * -N - Nth lines at bottom. 45863803Snsayer */ 459213028Sjhb 460158697Semax if (diff < -size.tp_row || diff > size.tp_row) { 461121816Sbrooks vw->vw_device->vd_flags |= VDF_INVALID; 462183397Sed vt_resume_flush_timer(vw->vw_device, 0); 46363670Snsayer return; 46463670Snsayer } 46563670Snsayer vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/ 46663670Snsayer vt_resume_flush_timer(vw->vw_device, 0); 467111742Sdes} 46863670Snsayer 46963670Snsayerstatic int 47063670Snsayervt_machine_kbdevent(int c) 47163670Snsayer{ 472156783Semax 47363670Snsayer switch (c) { 47463670Snsayer case SPCLKEY | DBG: 475133460Semax kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 476213028Sjhb return (1); 47763670Snsayer case SPCLKEY | RBT: 478164033Srwatson /* XXX: Make this configurable! */ 479164033Srwatson shutdown_nice(0); 480164033Srwatson return (1); 481164033Srwatson case SPCLKEY | HALT: 482164033Srwatson shutdown_nice(RB_HALT); 48363670Snsayer return (1); 484126796Sphk case SPCLKEY | PDWN: 485126796Sphk shutdown_nice(RB_HALT|RB_POWEROFF); 48683043Sbrooks return (1); 48763670Snsayer }; 48863670Snsayer 489127165Srwatson return (0); 490127165Srwatson} 491127165Srwatson 492127165Srwatsonstatic void 493127165Srwatsonvt_scrollmode_kbdevent(struct vt_window *vw, int c, int console) 49463670Snsayer{ 495152315Sru struct vt_device *vd; 49683366Sjulian term_pos_t size; 49763670Snsayer 498147256Sbrooks vd = vw->vw_device; 49963670Snsayer /* Only special keys handled in ScrollLock mode */ 500148887Srwatson if ((c & SPCLKEY) == 0) 501148887Srwatson return; 502167713Sbms 503167713Sbms c &= ~SPCLKEY; 504205024Sqingli 505213028Sjhb if (console == 0) { 50663670Snsayer if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 507183397Sed vw = vd->vd_windows[c - F_SCR]; 508133460Semax if (vw != NULL) 50963670Snsayer vt_proc_window_switch(vw); 51063670Snsayer return; 51163670Snsayer } 51263670Snsayer VT_LOCK(vd); 51363670Snsayer } 51463670Snsayer 51563670Snsayer switch (c) { 51663670Snsayer case SLK: { 51763670Snsayer /* Turn scrolling off. */ 51863670Snsayer vt_scroll(vw, 0, VHS_END); 519156783Semax VTBUF_SLCK_DISABLE(&vw->vw_buf); 52063670Snsayer vw->vw_flags &= ~VWF_SCROLL; 521156783Semax break; 52263670Snsayer } 523147256Sbrooks case FKEY | F(49): /* Home key. */ 52463670Snsayer vt_scroll(vw, 0, VHS_SET); 52563670Snsayer break; 526213028Sjhb case FKEY | F(50): /* Arrow up. */ 527236724Strociny vt_scroll(vw, -1, VHS_CUR); 52883043Sbrooks break; 52963670Snsayer case FKEY | F(51): /* Page up. */ 53063803Snsayer vt_termsize(vd, vw->vw_font, &size); 53163803Snsayer vt_scroll(vw, -size.tp_row, VHS_CUR); 53263803Snsayer break; 53363803Snsayer case FKEY | F(57): /* End key. */ 53463803Snsayer vt_scroll(vw, 0, VHS_END); 53563803Snsayer break; 536127098Srwatson case FKEY | F(58): /* Arrow down. */ 53763670Snsayer vt_scroll(vw, 1, VHS_CUR); 538213028Sjhb break; 539148887Srwatson case FKEY | F(59): /* Page down. */ 540213028Sjhb vt_termsize(vd, vw->vw_font, &size); 541213028Sjhb vt_scroll(vw, size.tp_row, VHS_CUR); 54263803Snsayer break; 543146620Speadar } 54463670Snsayer 545146620Speadar if (console == 0) 546213028Sjhb VT_UNLOCK(vd); 54763670Snsayer} 548213028Sjhb 54963670Snsayerstatic int 550205024Sqinglivt_processkey(keyboard_t *kbd, struct vt_device *vd, int c) 551236724Strociny{ 552236724Strociny struct vt_window *vw = vd->vd_curwindow; 55396122Salfred int state = 0; 554122352Stanimura 555213028Sjhb#if VT_ALT_TO_ESC_HACK 55663670Snsayer if (c & RELKEY) { 55763670Snsayer switch (c & ~RELKEY) { 55863670Snsayer case (SPCLKEY | RALT): 559127098Srwatson if (vt_enable_altgr != 0) 56063670Snsayer break; 561121816Sbrooks case (SPCLKEY | LALT): 562183397Sed vd->vd_kbstate &= ~ALKED; 56363670Snsayer } 56463670Snsayer /* Other keys ignored for RELKEY event. */ 56563670Snsayer return (0); 56663670Snsayer } else { 56763670Snsayer switch (c & ~RELKEY) { 56863670Snsayer case (SPCLKEY | RALT): 56963670Snsayer if (vt_enable_altgr != 0) 57063670Snsayer break; 57163670Snsayer case (SPCLKEY | LALT): 57263670Snsayer vd->vd_kbstate |= ALKED; 57363670Snsayer } 574156783Semax } 57563670Snsayer#else 57663670Snsayer if (c & RELKEY) 577147256Sbrooks /* Other keys ignored for RELKEY event. */ 57863670Snsayer return (0); 579121816Sbrooks#endif 58063670Snsayer 581213028Sjhb if (vt_machine_kbdevent(c)) 582148887Srwatson return (0); 583148887Srwatson 584213028Sjhb if (vw->vw_flags & VWF_SCROLL) { 58563670Snsayer vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 58663670Snsayer /* Scroll mode keys handled, nothing to do more. */ 58763670Snsayer return (0); 58863670Snsayer } 58963670Snsayer 59063670Snsayer if (c & SPCLKEY) { 59163670Snsayer c &= ~SPCLKEY; 59263670Snsayer 59363670Snsayer if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 59463670Snsayer vw = vd->vd_windows[c - F_SCR]; 59563670Snsayer if (vw != NULL) 596105228Sphk vt_proc_window_switch(vw); 597156783Semax return (0); 59863670Snsayer } 599160376Sbrooks 600189866Sscf switch (c) { 60163670Snsayer case SLK: { 602238183Semaste 603238183Semaste kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 60463670Snsayer VT_LOCK(vd); 60563670Snsayer if (state & SLKED) { 60663670Snsayer /* Turn scrolling on. */ 60763670Snsayer vw->vw_flags |= VWF_SCROLL; 60863670Snsayer VTBUF_SLCK_ENABLE(&vw->vw_buf); 60983043Sbrooks } else { 61063670Snsayer /* Turn scrolling off. */ 611238183Semaste vw->vw_flags &= ~VWF_SCROLL; 612238183Semaste VTBUF_SLCK_DISABLE(&vw->vw_buf); 613238183Semaste vt_scroll(vw, 0, VHS_END); 614238183Semaste } 615238183Semaste VT_UNLOCK(vd); 616238183Semaste break; 617238183Semaste } 618238183Semaste case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 619238183Semaste case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 620238183Semaste case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 621238183Semaste case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 622238183Semaste /* F1 through F12 keys. */ 623238183Semaste terminal_input_special(vw->vw_terminal, 624238183Semaste TKEY_F1 + c - (FKEY | F(1))); 625238183Semaste break; 626238183Semaste case FKEY | F(49): /* Home key. */ 627189866Sscf terminal_input_special(vw->vw_terminal, TKEY_HOME); 628189866Sscf break; 629189866Sscf case FKEY | F(50): /* Arrow up. */ 630189866Sscf terminal_input_special(vw->vw_terminal, TKEY_UP); 63163670Snsayer break; 63263670Snsayer case FKEY | F(51): /* Page up. */ 63363670Snsayer terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 634127098Srwatson break; 63563670Snsayer case FKEY | F(53): /* Arrow left. */ 63663670Snsayer terminal_input_special(vw->vw_terminal, TKEY_LEFT); 63763670Snsayer break; 63863670Snsayer case FKEY | F(55): /* Arrow right. */ 639127098Srwatson terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 64083043Sbrooks break; 64163670Snsayer case FKEY | F(57): /* End key. */ 64263670Snsayer terminal_input_special(vw->vw_terminal, TKEY_END); 643238183Semaste break; 644238183Semaste case FKEY | F(58): /* Arrow down. */ 64563670Snsayer terminal_input_special(vw->vw_terminal, TKEY_DOWN); 64663670Snsayer break; 647238183Semaste case FKEY | F(59): /* Page down. */ 64863670Snsayer terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 64963670Snsayer break; 65063670Snsayer case FKEY | F(60): /* Insert key. */ 65163670Snsayer terminal_input_special(vw->vw_terminal, TKEY_INSERT); 652111742Sdes break; 653111742Sdes case FKEY | F(61): /* Delete key. */ 65463670Snsayer terminal_input_special(vw->vw_terminal, TKEY_DELETE); 65563670Snsayer break; 65663670Snsayer } 657156783Semax } else if (KEYFLAGS(c) == 0) { 65863670Snsayer /* Don't do UTF-8 conversion when doing raw mode. */ 65963670Snsayer if (vw->vw_kbdmode == K_XLATE) { 66063670Snsayer#if VT_ALT_TO_ESC_HACK 661121816Sbrooks if (vd->vd_kbstate & ALKED) { 66263670Snsayer /* 66363803Snsayer * Prepend ESC sequence if one of ALT keys down. 66463803Snsayer */ 66563803Snsayer terminal_input_char(vw->vw_terminal, 0x1b); 66663803Snsayer } 66763803Snsayer#endif 668127098Srwatson 669111742Sdes terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 67063803Snsayer } else 671213028Sjhb terminal_input_raw(vw->vw_terminal, c); 67263670Snsayer } 673127098Srwatson return (0); 674121816Sbrooks} 675121816Sbrooks 67663670Snsayerstatic int 677213028Sjhbvt_kbdevent(keyboard_t *kbd, int event, void *arg) 67863670Snsayer{ 679213028Sjhb struct vt_device *vd = arg; 68063670Snsayer int c; 681213028Sjhb 682213028Sjhb switch (event) { 683213028Sjhb case KBDIO_KEYINPUT: 684213028Sjhb break; 685213028Sjhb case KBDIO_UNLOADING: 68663670Snsayer mtx_lock(&Giant); 68763670Snsayer vd->vd_keyboard = -1; 68863670Snsayer kbd_release(kbd, (void *)vd); 68963670Snsayer mtx_unlock(&Giant); 690148887Srwatson return (0); 69163670Snsayer default: 692213028Sjhb return (EINVAL); 69363670Snsayer } 69463670Snsayer 695111748Sdes while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 69663670Snsayer vt_processkey(kbd, vd, c); 69763670Snsayer 698127098Srwatson return (0); 699127098Srwatson} 70095883Salfred 701213028Sjhbstatic int 702213028Sjhbvt_allocate_keyboard(struct vt_device *vd) 70363670Snsayer{ 704122352Stanimura int idx0, idx; 705213028Sjhb keyboard_t *k0, *k; 70663670Snsayer keyboard_info_t ki; 70763670Snsayer 70863670Snsayer idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd); 709148887Srwatson vd->vd_keyboard = idx0; 710213028Sjhb if (idx0 >= 0) { 71163670Snsayer DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 71263670Snsayer k0 = kbd_get_keyboard(idx0); 71363670Snsayer 71463670Snsayer for (idx = kbd_find_keyboard2("*", -1, 0); 71563670Snsayer idx != -1; 71663670Snsayer idx = kbd_find_keyboard2("*", -1, idx + 1)) { 71763670Snsayer k = kbd_get_keyboard(idx); 71863670Snsayer 71963670Snsayer if (idx == idx0 || KBD_IS_BUSY(k)) 720156783Semax continue; 72163670Snsayer 72263670Snsayer bzero(&ki, sizeof(ki)); 723147256Sbrooks strcpy(ki.kb_name, k->kb_name); 724111742Sdes ki.kb_unit = k->kb_unit; 725102052Ssobomax 726162711Sru kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 727162711Sru } 728162711Sru } else { 729162711Sru DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 73063670Snsayer idx0 = kbd_allocate("*", -1, vd, vt_kbdevent, vd); 73163670Snsayer if (idx0 < 0) { 732111742Sdes DPRINTF(10, "%s: No keyboard found.\n", __func__); 733111742Sdes return (-1); 734213028Sjhb } 735111742Sdes } 736111742Sdes DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 737111742Sdes 738213028Sjhb return (idx0); 739111742Sdes} 74063670Snsayer 741111742Sdesstatic void 742111742Sdesvtterm_bell(struct terminal *tm) 743213028Sjhb{ 744111742Sdes struct vt_window *vw = tm->tm_softc; 745111742Sdes struct vt_device *vd = vw->vw_device; 746111742Sdes 747213028Sjhb if (vd->vd_flags & VDF_QUIET_BELL) 748111742Sdes return; 74963670Snsayer 75063670Snsayer sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION); 751159079Smarius} 75283043Sbrooks 75363670Snsayerstatic void 75463670Snsayervtterm_beep(struct terminal *tm, u_int param) 755159079Smarius{ 75683043Sbrooks u_int freq, period; 75763670Snsayer 758182880Semax if ((param == 0) || ((param & 0xffff) == 0)) { 759182880Semax vtterm_bell(tm); 760182880Semax return; 761182880Semax } 762182880Semax 763182880Semax period = ((param >> 16) & 0xffff) * hz / 1000; 76463670Snsayer freq = 1193182 / (param & 0xffff); 76583043Sbrooks 76663670Snsayer sysbeep(freq, period); 76763670Snsayer} 768127098Srwatson 769159079Smariusstatic void 77063670Snsayervtterm_cursor(struct terminal *tm, const term_pos_t *p) 77163670Snsayer{ 77263670Snsayer struct vt_window *vw = tm->tm_softc; 773127098Srwatson 77483043Sbrooks vtbuf_cursor_position(&vw->vw_buf, p); 77563670Snsayer vt_resume_flush_timer(vw->vw_device, 0); 77663670Snsayer} 777213028Sjhb 778213028Sjhbstatic void 77963670Snsayervtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 780213028Sjhb{ 781213028Sjhb struct vt_window *vw = tm->tm_softc; 782213028Sjhb 783213028Sjhb vtbuf_putchar(&vw->vw_buf, p, c); 784159079Smarius vt_resume_flush_timer(vw->vw_device, 0); 785213028Sjhb} 78683043Sbrooks 787159079Smariusstatic void 78883043Sbrooksvtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 78963670Snsayer{ 79063670Snsayer struct vt_window *vw = tm->tm_softc; 791159079Smarius 79263670Snsayer vtbuf_fill_locked(&vw->vw_buf, r, c); 79363670Snsayer vt_resume_flush_timer(vw->vw_device, 0); 794159079Smarius} 79563670Snsayer 79663670Snsayerstatic void 79763670Snsayervtterm_copy(struct terminal *tm, const term_rect_t *r, 79863670Snsayer const term_pos_t *p) 799159079Smarius{ 80063670Snsayer struct vt_window *vw = tm->tm_softc; 80163670Snsayer 80263670Snsayer vtbuf_copy(&vw->vw_buf, r, p); 803159079Smarius vt_resume_flush_timer(vw->vw_device, 0); 80463670Snsayer} 80563670Snsayer 80663670Snsayerstatic void 80763670Snsayervtterm_param(struct terminal *tm, int cmd, unsigned int arg) 808162711Sru{ 809162711Sru struct vt_window *vw = tm->tm_softc; 810162711Sru 811162711Sru switch (cmd) { 812162711Sru case TP_SHOWCURSOR: 813162711Sru vtbuf_cursor_visibility(&vw->vw_buf, arg); 814162711Sru vt_resume_flush_timer(vw->vw_device, 0); 81583043Sbrooks break; 816162711Sru case TP_MOUSE: 81763670Snsayer vw->vw_mouse_level = arg; 81863670Snsayer break; 81963670Snsayer } 82063670Snsayer} 821213028Sjhb 82263670Snsayervoid 823213028Sjhbvt_determine_colors(term_char_t c, int cursor, 82483043Sbrooks term_color_t *fg, term_color_t *bg) 82563670Snsayer{ 82663861Snsayer term_color_t tmp; 82763670Snsayer int invert; 828127165Srwatson 82963861Snsayer invert = 0; 830127165Srwatson 83183043Sbrooks *fg = TCHAR_FGCOLOR(c); 83263670Snsayer if (TCHAR_FORMAT(c) & TF_BOLD) 83363861Snsayer *fg = TCOLOR_LIGHT(*fg); 834127165Srwatson *bg = TCHAR_BGCOLOR(c); 83563861Snsayer 836127165Srwatson if (TCHAR_FORMAT(c) & TF_REVERSE) 83783043Sbrooks invert ^= 1; 83863670Snsayer if (cursor) 83963670Snsayer invert ^= 1; 84063670Snsayer 84163670Snsayer if (invert) { 84263670Snsayer tmp = *fg; 84363670Snsayer *fg = *bg; 84463670Snsayer *bg = tmp; 84563670Snsayer } 84663670Snsayer} 84763670Snsayer 84863670Snsayer#ifndef SC_NO_CUTPASTE 84963670Snsayerint 85063670Snsayervt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area) 85163670Snsayer{ 85263670Snsayer unsigned int mx, my, x1, y1, x2, y2; 853156783Semax 85463670Snsayer /* 85563670Snsayer * We use the cursor position saved during the current refresh, 856147256Sbrooks * in case the cursor moved since. 85790227Sdillon */ 858213028Sjhb mx = vd->vd_mx_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_col; 85963670Snsayer my = vd->vd_my_drawn + vd->vd_curwindow->vw_draw_area.tr_begin.tp_row; 860183397Sed 86163670Snsayer x1 = area->tr_begin.tp_col; 862127098Srwatson y1 = area->tr_begin.tp_row; 86363670Snsayer x2 = area->tr_end.tp_col; 864127098Srwatson y2 = area->tr_end.tp_row; 865127098Srwatson 866127098Srwatson if (((mx >= x1 && x2 - 1 >= mx) || 867121816Sbrooks (mx < x1 && mx + vd->vd_mcursor->width >= x1)) && 868183397Sed ((my >= y1 && y2 - 1 >= my) || 86963803Snsayer (my < y1 && my + vd->vd_mcursor->height >= y1))) 87063670Snsayer return (1); 87163670Snsayer 87263670Snsayer return (0); 87363670Snsayer} 87463670Snsayer 87563670Snsayerstatic void 87663670Snsayervt_mark_mouse_position_as_dirty(struct vt_device *vd) 87790227Sdillon{ 87863670Snsayer term_rect_t area; 87990227Sdillon struct vt_window *vw; 880213028Sjhb struct vt_font *vf; 881213028Sjhb int x, y; 88263670Snsayer 883213028Sjhb vw = vd->vd_curwindow; 884111742Sdes vf = vw->vw_font; 88563670Snsayer 886213028Sjhb x = vd->vd_mx_drawn; 887213028Sjhb y = vd->vd_my_drawn; 888213028Sjhb 889213028Sjhb if (vf != NULL) { 89063670Snsayer area.tr_begin.tp_col = x / vf->vf_width; 891213028Sjhb area.tr_begin.tp_row = y / vf->vf_height; 89263670Snsayer area.tr_end.tp_col = 89390227Sdillon ((x + vd->vd_mcursor->width) / vf->vf_width) + 1; 894213028Sjhb area.tr_end.tp_row = 89563670Snsayer ((y + vd->vd_mcursor->height) / vf->vf_height) + 1; 89663670Snsayer } else { 897106939Ssam /* 89863670Snsayer * No font loaded (ie. vt_vga operating in textmode). 89963670Snsayer * 90090227Sdillon * FIXME: This fake area needs to be revisited once the 90190227Sdillon * mouse cursor is supported in vt_vga's textmode. 90263670Snsayer */ 90363670Snsayer area.tr_begin.tp_col = x; 90463670Snsayer area.tr_begin.tp_row = y; 905111741Sdes area.tr_end.tp_col = x + 2; 90690227Sdillon area.tr_end.tp_row = y + 2; 90763670Snsayer } 90863670Snsayer 90990227Sdillon vtbuf_dirty(&vw->vw_buf, &area); 910121816Sbrooks} 911183397Sed#endif 91290227Sdillon 91363670Snsayerstatic int 91463670Snsayervt_flush(struct vt_device *vd) 91563670Snsayer{ 91663670Snsayer struct vt_window *vw; 91763670Snsayer struct vt_font *vf; 91863670Snsayer struct vt_bufmask tmask; 91963670Snsayer term_rect_t tarea; 92063670Snsayer term_pos_t size; 92163670Snsayer#ifndef SC_NO_CUTPASTE 92263670Snsayer int cursor_was_shown, cursor_moved; 92363670Snsayer#endif 92463670Snsayer 925156783Semax vw = vd->vd_curwindow; 92663670Snsayer if (vw == NULL) 927166443Sbms return (0); 92863670Snsayer 929147256Sbrooks if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY) 930137101Sglebius return (0); 93163670Snsayer 932121816Sbrooks vf = vw->vw_font; 933183397Sed if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL)) 93463670Snsayer return (0); 93563670Snsayer 93663670Snsayer#ifndef SC_NO_CUTPASTE 93763670Snsayer cursor_was_shown = vd->vd_mshown; 93863670Snsayer cursor_moved = (vd->vd_mx != vd->vd_mx_drawn || 939194990Skib vd->vd_my != vd->vd_my_drawn); 940183397Sed 94163803Snsayer /* Check if the cursor should be displayed or not. */ 94263670Snsayer if ((vd->vd_flags & VDF_MOUSECURSOR) && /* Mouse support enabled. */ 94363670Snsayer !(vw->vw_flags & VWF_MOUSE_HIDE) && /* Cursor displayed. */ 94463670Snsayer !kdb_active && panicstr == NULL) { /* DDB inactive. */ 945163915Sandre vd->vd_mshown = 1; 946163915Sandre } else { 94763670Snsayer vd->vd_mshown = 0; 948163986Scsjp } 94963670Snsayer 95063670Snsayer /* 951137101Sglebius * If the cursor changed display state or moved, we must mark 952111742Sdes * the old position as dirty, so that it's erased. 953166443Sbms */ 954166443Sbms if (cursor_was_shown != vd->vd_mshown || 955166443Sbms (vd->vd_mshown && cursor_moved)) 956166443Sbms vt_mark_mouse_position_as_dirty(vd); 957166443Sbms 958166443Sbms /* 959166443Sbms * Save position of the mouse cursor. It's used by backends to 960166443Sbms * know where to draw the cursor and during the next refresh to 961166443Sbms * erase the previous position. 962166443Sbms */ 963166443Sbms vd->vd_mx_drawn = vd->vd_mx; 964166443Sbms vd->vd_my_drawn = vd->vd_my; 965166443Sbms 966166443Sbms /* 967166443Sbms * If the cursor is displayed and has moved since last refresh, 968166443Sbms * mark the new position as dirty. 969166443Sbms */ 970106939Ssam if (vd->vd_mshown && cursor_moved) 971236724Strociny vt_mark_mouse_position_as_dirty(vd); 972137101Sglebius#endif 973236724Strociny 974106939Ssam vtbuf_undirty(&vw->vw_buf, &tarea, &tmask); 97563670Snsayer vt_termsize(vd, vf, &size); 97663670Snsayer 97763670Snsayer /* Force a full redraw when the screen contents are invalid. */ 97863670Snsayer if (vd->vd_flags & VDF_INVALID) { 97963670Snsayer tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0; 98063670Snsayer tarea.tr_end = size; 98163670Snsayer tmask.vbm_row = tmask.vbm_col = VBM_DIRTY; 98263670Snsayer 98363670Snsayer vd->vd_flags &= ~VDF_INVALID; 98463670Snsayer } 98563670Snsayer 98663670Snsayer if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) { 98763670Snsayer vd->vd_driver->vd_bitblt_text(vd, vw, &tarea); 988156783Semax return (1); 98963670Snsayer } 99063670Snsayer 991147256Sbrooks return (0); 992213028Sjhb} 99363670Snsayer 994121816Sbrooksstatic void 995183397Sedvt_timer(void *arg) 99663670Snsayer{ 99763670Snsayer struct vt_device *vd; 998213028Sjhb int changed; 999213028Sjhb 1000121816Sbrooks vd = arg; 1001121816Sbrooks /* Update screen if required. */ 1002183397Sed changed = vt_flush(vd); 100363803Snsayer 100463670Snsayer /* Schedule for next update. */ 100583043Sbrooks if (changed) 1006121816Sbrooks vt_schedule_flush(vd, 0); 1007183397Sed else 100863803Snsayer vd->vd_timer_armed = 0; 100983805Sjhb} 101063670Snsayer 1011213028Sjhbstatic void 101263670Snsayervtterm_done(struct terminal *tm) 101363670Snsayer{ 101463670Snsayer struct vt_window *vw = tm->tm_softc; 101563670Snsayer struct vt_device *vd = vw->vw_device; 101663670Snsayer 101763670Snsayer if (kdb_active || panicstr != NULL) { 101863670Snsayer /* Switch to the debugger. */ 1019156783Semax if (vd->vd_curwindow != vw) { 1020156783Semax vd->vd_curwindow = vw; 1021156783Semax vd->vd_flags |= VDF_INVALID; 1022156783Semax if (vd->vd_driver->vd_postswitch) 1023156783Semax vd->vd_driver->vd_postswitch(vd); 1024156783Semax } 1025156783Semax vd->vd_flags &= ~VDF_SPLASH; 1026156783Semax vt_flush(vd); 1027156783Semax } else if (!(vd->vd_flags & VDF_ASYNC)) { 1028156783Semax vt_flush(vd); 1029156783Semax } 1030156783Semax} 1031156783Semax 1032156783Semax#ifdef DEV_SPLASH 1033156783Semaxstatic void 1034156783Semaxvtterm_splash(struct vt_device *vd) 1035183397Sed{ 1036156783Semax vt_axis_t top, left; 1037156783Semax 1038156783Semax /* Display a nice boot splash. */ 1039156783Semax if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) { 1040156783Semax 1041183397Sed top = (vd->vd_height - vt_logo_height) / 2; 1042156783Semax left = (vd->vd_width - vt_logo_width) / 2; 1043156783Semax switch (vt_logo_depth) { 1044156783Semax case 1: 1045156783Semax /* XXX: Unhardcode colors! */ 1046156783Semax vd->vd_driver->vd_bitblt_bmp(vd, vd->vd_curwindow, 1047183397Sed vt_logo_image, NULL, vt_logo_width, vt_logo_height, 1048156783Semax left, top, TC_WHITE, TC_BLACK); 1049156783Semax } 1050156783Semax vd->vd_flags |= VDF_SPLASH; 1051156783Semax } 1052213028Sjhb} 1053156783Semax#endif 1054156783Semax 1055156783Semax 1056156783Semaxstatic void 1057156783Semaxvtterm_cnprobe(struct terminal *tm, struct consdev *cp) 1058156783Semax{ 1059156783Semax struct vt_driver *vtd, **vtdlist, *vtdbest = NULL; 1060156783Semax struct vt_window *vw = tm->tm_softc; 1061156783Semax struct vt_device *vd = vw->vw_device; 1062156783Semax struct winsize wsz; 1063156783Semax term_attr_t attr; 1064156783Semax term_char_t c; 1065156783Semax 1066156783Semax if (!vty_enabled(VTY_VT)) 1067213028Sjhb return; 1068213028Sjhb 1069213028Sjhb if (vd->vd_flags & VDF_INITIALIZED) 1070156783Semax /* Initialization already done. */ 1071156783Semax return; 1072156783Semax 1073156783Semax SET_FOREACH(vtdlist, vt_drv_set) { 1074183397Sed vtd = *vtdlist; 1075156783Semax if (vtd->vd_probe == NULL) 1076156783Semax continue; 1077156783Semax if (vtd->vd_probe(vd) == CN_DEAD) 1078183397Sed continue; 1079156783Semax if ((vtdbest == NULL) || 1080156783Semax (vtd->vd_priority > vtdbest->vd_priority)) 1081156783Semax vtdbest = vtd; 1082156783Semax } 1083156783Semax if (vtdbest == NULL) { 1084156783Semax cp->cn_pri = CN_DEAD; 1085156783Semax vd->vd_flags |= VDF_DEAD; 1086156783Semax } else { 1087156783Semax vd->vd_driver = vtdbest; 1088156783Semax cp->cn_pri = vd->vd_driver->vd_init(vd); 1089156783Semax } 1090156783Semax 1091156783Semax /* Check if driver's vt_init return CN_DEAD. */ 1092156783Semax if (cp->cn_pri == CN_DEAD) { 1093156783Semax vd->vd_flags |= VDF_DEAD; 1094213028Sjhb } 1095156783Semax 1096156783Semax /* Initialize any early-boot keyboard drivers */ 1097156783Semax kbd_configure(KB_CONF_PROBE_ONLY); 1098156783Semax 1099156783Semax vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 1100156783Semax vd->vd_windows[VT_CONSWINDOW] = vw; 1101156783Semax sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 1102156783Semax 1103156783Semax /* Attach default font if not in TEXTMODE. */ 1104156783Semax if ((vd->vd_flags & VDF_TEXTMODE) == 0) { 1105156783Semax vw->vw_font = vtfont_ref(&vt_font_default); 1106213028Sjhb vt_compute_drawable_area(vw); 1107156783Semax } 1108156783Semax 1109156783Semax vtbuf_init_early(&vw->vw_buf); 1110156783Semax vt_winsize(vd, vw->vw_font, &wsz); 1111 c = (boothowto & RB_MUTE) == 0 ? TERMINAL_KERN_ATTR : 1112 TERMINAL_NORM_ATTR; 1113 attr.ta_format = TCHAR_FORMAT(c); 1114 attr.ta_fgcolor = TCHAR_FGCOLOR(c); 1115 attr.ta_bgcolor = TCHAR_BGCOLOR(c); 1116 terminal_set_winsize_blank(tm, &wsz, 1, &attr); 1117 1118 if (vtdbest != NULL) { 1119#ifdef DEV_SPLASH 1120 vtterm_splash(vd); 1121#endif 1122 vd->vd_flags |= VDF_INITIALIZED; 1123 } 1124} 1125 1126static int 1127vtterm_cngetc(struct terminal *tm) 1128{ 1129 struct vt_window *vw = tm->tm_softc; 1130 struct vt_device *vd = vw->vw_device; 1131 keyboard_t *kbd; 1132 int state; 1133 u_int c; 1134 1135 if (vw->vw_kbdsq && *vw->vw_kbdsq) 1136 return (*vw->vw_kbdsq++); 1137 1138 state = 0; 1139 /* Make sure the splash screen is not there. */ 1140 if (vd->vd_flags & VDF_SPLASH) { 1141 /* Remove splash */ 1142 vd->vd_flags &= ~VDF_SPLASH; 1143 /* Mark screen as invalid to force update */ 1144 vd->vd_flags |= VDF_INVALID; 1145 vt_flush(vd); 1146 } 1147 1148 /* Stripped down keyboard handler. */ 1149 kbd = kbd_get_keyboard(vd->vd_keyboard); 1150 if (kbd == NULL) 1151 return (-1); 1152 1153 /* Force keyboard input mode to K_XLATE */ 1154 c = K_XLATE; 1155 kbdd_ioctl(kbd, KDSKBMODE, (void *)&c); 1156 1157 /* Switch the keyboard to polling to make it work here. */ 1158 kbdd_poll(kbd, TRUE); 1159 c = kbdd_read_char(kbd, 0); 1160 kbdd_poll(kbd, FALSE); 1161 if (c & RELKEY) 1162 return (-1); 1163 1164 if (vw->vw_flags & VWF_SCROLL) { 1165 vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 1166 vt_flush(vd); 1167 return (-1); 1168 } 1169 1170 /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 1171 if (c & SPCLKEY) { 1172 switch (c) { 1173 case SPCLKEY | SLK: 1174 kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 1175 if (state & SLKED) { 1176 /* Turn scrolling on. */ 1177 vw->vw_flags |= VWF_SCROLL; 1178 VTBUF_SLCK_ENABLE(&vw->vw_buf); 1179 } else { 1180 /* Turn scrolling off. */ 1181 vt_scroll(vw, 0, VHS_END); 1182 vw->vw_flags &= ~VWF_SCROLL; 1183 VTBUF_SLCK_DISABLE(&vw->vw_buf); 1184 } 1185 break; 1186 /* XXX: KDB can handle history. */ 1187 case SPCLKEY | FKEY | F(50): /* Arrow up. */ 1188 vw->vw_kbdsq = "\x1b[A"; 1189 break; 1190 case SPCLKEY | FKEY | F(58): /* Arrow down. */ 1191 vw->vw_kbdsq = "\x1b[B"; 1192 break; 1193 case SPCLKEY | FKEY | F(55): /* Arrow right. */ 1194 vw->vw_kbdsq = "\x1b[C"; 1195 break; 1196 case SPCLKEY | FKEY | F(53): /* Arrow left. */ 1197 vw->vw_kbdsq = "\x1b[D"; 1198 break; 1199 } 1200 1201 /* Force refresh to make scrollback work. */ 1202 vt_flush(vd); 1203 } else if (KEYFLAGS(c) == 0) { 1204 return (KEYCHAR(c)); 1205 } 1206 1207 if (vw->vw_kbdsq && *vw->vw_kbdsq) 1208 return (*vw->vw_kbdsq++); 1209 1210 return (-1); 1211} 1212 1213static void 1214vtterm_opened(struct terminal *tm, int opened) 1215{ 1216 struct vt_window *vw = tm->tm_softc; 1217 struct vt_device *vd = vw->vw_device; 1218 1219 VT_LOCK(vd); 1220 vd->vd_flags &= ~VDF_SPLASH; 1221 if (opened) 1222 vw->vw_flags |= VWF_OPENED; 1223 else { 1224 vw->vw_flags &= ~VWF_OPENED; 1225 /* TODO: finish ACQ/REL */ 1226 } 1227 VT_UNLOCK(vd); 1228} 1229 1230static int 1231vt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c) 1232{ 1233 struct vt_device *vd = vw->vw_device; 1234 int x, y, off_x, off_y; 1235 1236 if (vd->vd_driver->vd_drawrect == NULL) 1237 return (ENOTSUP); 1238 1239 x = vd->vd_width - 1; 1240 y = vd->vd_height - 1; 1241 off_x = vw->vw_draw_area.tr_begin.tp_col; 1242 off_y = vw->vw_draw_area.tr_begin.tp_row; 1243 1244 /* Top bar. */ 1245 if (off_y > 0) 1246 vd->vd_driver->vd_drawrect(vd, 0, 0, x, off_y - 1, 1, c); 1247 /* Left bar. */ 1248 if (off_x > 0) 1249 vd->vd_driver->vd_drawrect(vd, 0, off_y, off_x - 1, y - off_y, 1250 1, c); 1251 /* Right bar. May be 1 pixel wider than necessary due to rounding. */ 1252 vd->vd_driver->vd_drawrect(vd, x - off_x, off_y, x, y - off_y, 1, c); 1253 /* Bottom bar. May be 1 mixel taller than necessary due to rounding. */ 1254 vd->vd_driver->vd_drawrect(vd, 0, y - off_y, x, y, 1, c); 1255 1256 return (0); 1257} 1258 1259static int 1260vt_change_font(struct vt_window *vw, struct vt_font *vf) 1261{ 1262 struct vt_device *vd = vw->vw_device; 1263 struct terminal *tm = vw->vw_terminal; 1264 term_pos_t size; 1265 struct winsize wsz; 1266 1267 /* 1268 * Changing fonts. 1269 * 1270 * Changing fonts is a little tricky. We must prevent 1271 * simultaneous access to the device, so we must stop 1272 * the display timer and the terminal from accessing. 1273 * We need to switch fonts and grow our screen buffer. 1274 * 1275 * XXX: Right now the code uses terminal_mute() to 1276 * prevent data from reaching the console driver while 1277 * resizing the screen buffer. This isn't elegant... 1278 */ 1279 1280 VT_LOCK(vd); 1281 if (vw->vw_flags & VWF_BUSY) { 1282 /* Another process is changing the font. */ 1283 VT_UNLOCK(vd); 1284 return (EBUSY); 1285 } 1286 if (vd->vd_flags & VDF_TEXTMODE) { 1287 /* Our device doesn't need fonts. */ 1288 VT_UNLOCK(vd); 1289 return (ENOTTY); 1290 } 1291 vw->vw_flags |= VWF_BUSY; 1292 VT_UNLOCK(vd); 1293 1294 vt_termsize(vd, vf, &size); 1295 vt_winsize(vd, vf, &wsz); 1296 1297 /* Grow the screen buffer and terminal. */ 1298 terminal_mute(tm, 1); 1299 vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 1300 terminal_set_winsize_blank(tm, &wsz, 0, NULL); 1301 terminal_mute(tm, 0); 1302 1303 /* Actually apply the font to the current window. */ 1304 VT_LOCK(vd); 1305 if (vw->vw_font != vf) { 1306 /* 1307 * In case vt_change_font called to update size we don't need 1308 * to update font link. 1309 */ 1310 vtfont_unref(vw->vw_font); 1311 vw->vw_font = vtfont_ref(vf); 1312 } 1313 1314 /* 1315 * Compute the drawable area and move the mouse cursor inside 1316 * it, in case the new area is smaller than the previous one. 1317 */ 1318 vt_compute_drawable_area(vw); 1319 vd->vd_mx = min(vd->vd_mx, 1320 vw->vw_draw_area.tr_end.tp_col - 1321 vw->vw_draw_area.tr_begin.tp_col - 1); 1322 vd->vd_my = min(vd->vd_my, 1323 vw->vw_draw_area.tr_end.tp_row - 1324 vw->vw_draw_area.tr_begin.tp_row - 1); 1325 1326 /* Force a full redraw the next timer tick. */ 1327 if (vd->vd_curwindow == vw) { 1328 vt_set_border(vw, vf, TC_BLACK); 1329 vd->vd_flags |= VDF_INVALID; 1330 vt_resume_flush_timer(vw->vw_device, 0); 1331 } 1332 vw->vw_flags &= ~VWF_BUSY; 1333 VT_UNLOCK(vd); 1334 return (0); 1335} 1336 1337static int 1338vt_proc_alive(struct vt_window *vw) 1339{ 1340 struct proc *p; 1341 1342 if (vw->vw_smode.mode != VT_PROCESS) 1343 return (FALSE); 1344 1345 if (vw->vw_proc) { 1346 if ((p = pfind(vw->vw_pid)) != NULL) 1347 PROC_UNLOCK(p); 1348 if (vw->vw_proc == p) 1349 return (TRUE); 1350 vw->vw_proc = NULL; 1351 vw->vw_smode.mode = VT_AUTO; 1352 DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 1353 vw->vw_pid = 0; 1354 } 1355 return (FALSE); 1356} 1357 1358static int 1359signal_vt_rel(struct vt_window *vw) 1360{ 1361 1362 if (vw->vw_smode.mode != VT_PROCESS) 1363 return (FALSE); 1364 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1365 vw->vw_proc = NULL; 1366 vw->vw_pid = 0; 1367 return (TRUE); 1368 } 1369 vw->vw_flags |= VWF_SWWAIT_REL; 1370 PROC_LOCK(vw->vw_proc); 1371 kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 1372 PROC_UNLOCK(vw->vw_proc); 1373 DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 1374 return (TRUE); 1375} 1376 1377static int 1378signal_vt_acq(struct vt_window *vw) 1379{ 1380 1381 if (vw->vw_smode.mode != VT_PROCESS) 1382 return (FALSE); 1383 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1384 cnavailable(vw->vw_terminal->consdev, FALSE); 1385 if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1386 vw->vw_proc = NULL; 1387 vw->vw_pid = 0; 1388 return (TRUE); 1389 } 1390 vw->vw_flags |= VWF_SWWAIT_ACQ; 1391 PROC_LOCK(vw->vw_proc); 1392 kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1393 PROC_UNLOCK(vw->vw_proc); 1394 DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1395 return (TRUE); 1396} 1397 1398static int 1399finish_vt_rel(struct vt_window *vw, int release, int *s) 1400{ 1401 1402 if (vw->vw_flags & VWF_SWWAIT_REL) { 1403 vw->vw_flags &= ~VWF_SWWAIT_REL; 1404 if (release) { 1405 callout_drain(&vw->vw_proc_dead_timer); 1406 vt_late_window_switch(vw->vw_switch_to); 1407 } 1408 return (0); 1409 } 1410 return (EINVAL); 1411} 1412 1413static int 1414finish_vt_acq(struct vt_window *vw) 1415{ 1416 1417 if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1418 vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1419 return (0); 1420 } 1421 return (EINVAL); 1422} 1423 1424#ifndef SC_NO_CUTPASTE 1425static void 1426vt_mouse_terminput_button(struct vt_device *vd, int button) 1427{ 1428 struct vt_window *vw; 1429 struct vt_font *vf; 1430 char mouseb[6] = "\x1B[M"; 1431 int i, x, y; 1432 1433 vw = vd->vd_curwindow; 1434 vf = vw->vw_font; 1435 1436 /* Translate to char position. */ 1437 x = vd->vd_mx / vf->vf_width; 1438 y = vd->vd_my / vf->vf_height; 1439 /* Avoid overflow. */ 1440 x = MIN(x, 255 - '!'); 1441 y = MIN(y, 255 - '!'); 1442 1443 mouseb[3] = ' ' + button; 1444 mouseb[4] = '!' + x; 1445 mouseb[5] = '!' + y; 1446 1447 for (i = 0; i < sizeof(mouseb); i++ ) 1448 terminal_input_char(vw->vw_terminal, mouseb[i]); 1449} 1450 1451static void 1452vt_mouse_terminput(struct vt_device *vd, int type, int x, int y, int event, 1453 int cnt) 1454{ 1455 1456 switch (type) { 1457 case MOUSE_BUTTON_EVENT: 1458 if (cnt > 0) { 1459 /* Mouse button pressed. */ 1460 if (event & MOUSE_BUTTON1DOWN) 1461 vt_mouse_terminput_button(vd, 0); 1462 if (event & MOUSE_BUTTON2DOWN) 1463 vt_mouse_terminput_button(vd, 1); 1464 if (event & MOUSE_BUTTON3DOWN) 1465 vt_mouse_terminput_button(vd, 2); 1466 } else { 1467 /* Mouse button released. */ 1468 vt_mouse_terminput_button(vd, 3); 1469 } 1470 break; 1471#ifdef notyet 1472 case MOUSE_MOTION_EVENT: 1473 if (mouse->u.data.z < 0) { 1474 /* Scroll up. */ 1475 sc_mouse_input_button(vd, 64); 1476 } else if (mouse->u.data.z > 0) { 1477 /* Scroll down. */ 1478 sc_mouse_input_button(vd, 65); 1479 } 1480 break; 1481#endif 1482 } 1483} 1484 1485void 1486vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel) 1487{ 1488 struct vt_device *vd; 1489 struct vt_window *vw; 1490 struct vt_font *vf; 1491 term_pos_t size; 1492 term_char_t *buf; 1493 int i, len, mark; 1494 1495 vd = main_vd; 1496 vw = vd->vd_curwindow; 1497 vf = vw->vw_font; 1498 mark = 0; 1499 1500 if (vw->vw_flags & (VWF_MOUSE_HIDE | VWF_GRAPHICS)) 1501 /* 1502 * Either the mouse is disabled, or the window is in 1503 * "graphics mode". The graphics mode is usually set by 1504 * an X server, using the KDSETMODE ioctl. 1505 */ 1506 return; 1507 1508 if (vf == NULL) /* Text mode. */ 1509 return; 1510 1511 /* 1512 * TODO: add flag about pointer position changed, to not redraw chars 1513 * under mouse pointer when nothing changed. 1514 */ 1515 1516 if (vw->vw_mouse_level > 0) 1517 vt_mouse_terminput(vd, type, x, y, event, cnt); 1518 1519 switch (type) { 1520 case MOUSE_ACTION: 1521 case MOUSE_MOTION_EVENT: 1522 /* Movement */ 1523 x += vd->vd_mx; 1524 y += vd->vd_my; 1525 1526 vt_termsize(vd, vf, &size); 1527 1528 /* Apply limits. */ 1529 x = MAX(x, 0); 1530 y = MAX(y, 0); 1531 x = MIN(x, (size.tp_col * vf->vf_width) - 1); 1532 y = MIN(y, (size.tp_row * vf->vf_height) - 1); 1533 1534 vd->vd_mx = x; 1535 vd->vd_my = y; 1536 if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) && 1537 (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE, 1538 vd->vd_mx / vf->vf_width, 1539 vd->vd_my / vf->vf_height) == 1)) { 1540 1541 /* 1542 * We have something marked to copy, so update pointer 1543 * to window with selection. 1544 */ 1545 vd->vd_markedwin = vw; 1546 } 1547 1548 vt_resume_flush_timer(vw->vw_device, 0); 1549 return; /* Done */ 1550 case MOUSE_BUTTON_EVENT: 1551 /* Buttons */ 1552 break; 1553 default: 1554 return; /* Done */ 1555 } 1556 1557 switch (event) { 1558 case MOUSE_BUTTON1DOWN: 1559 switch (cnt % 4) { 1560 case 0: /* up */ 1561 mark = VTB_MARK_END; 1562 break; 1563 case 1: /* single click: start cut operation */ 1564 mark = VTB_MARK_START; 1565 break; 1566 case 2: /* double click: cut a word */ 1567 mark = VTB_MARK_WORD; 1568 break; 1569 case 3: /* triple click: cut a line */ 1570 mark = VTB_MARK_ROW; 1571 break; 1572 } 1573 break; 1574 case VT_MOUSE_PASTEBUTTON: 1575 switch (cnt) { 1576 case 0: /* up */ 1577 break; 1578 default: 1579 if (vd->vd_markedwin == NULL) 1580 return; 1581 /* Get current selecton size in bytes. */ 1582 len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf); 1583 if (len <= 0) 1584 return; 1585 1586 buf = malloc(len, M_VT, M_WAITOK | M_ZERO); 1587 /* Request cupy/paste buffer data, no more than `len' */ 1588 vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf, 1589 len); 1590 1591 len /= sizeof(term_char_t); 1592 for (i = 0; i < len; i++ ) { 1593 if (buf[i] == '\0') 1594 continue; 1595 terminal_input_char(vw->vw_terminal, buf[i]); 1596 } 1597 1598 /* Done, so cleanup. */ 1599 free(buf, M_VT); 1600 break; 1601 } 1602 return; /* Done */ 1603 case VT_MOUSE_EXTENDBUTTON: 1604 switch (cnt) { 1605 case 0: /* up */ 1606 if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 1607 mark = VTB_MARK_EXTEND; 1608 else 1609 mark = 0; 1610 break; 1611 default: 1612 mark = VTB_MARK_EXTEND; 1613 break; 1614 } 1615 break; 1616 default: 1617 return; /* Done */ 1618 } 1619 1620 /* Save buttons state. */ 1621 if (cnt > 0) 1622 vd->vd_mstate |= event; 1623 else 1624 vd->vd_mstate &= ~event; 1625 1626 if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 1627 vd->vd_my / vf->vf_height) == 1) { 1628 /* 1629 * We have something marked to copy, so update pointer to 1630 * window with selection. 1631 */ 1632 vd->vd_markedwin = vw; 1633 vt_resume_flush_timer(vw->vw_device, 0); 1634 } 1635} 1636 1637void 1638vt_mouse_state(int show) 1639{ 1640 struct vt_device *vd; 1641 struct vt_window *vw; 1642 1643 vd = main_vd; 1644 vw = vd->vd_curwindow; 1645 1646 switch (show) { 1647 case VT_MOUSE_HIDE: 1648 vw->vw_flags |= VWF_MOUSE_HIDE; 1649 break; 1650 case VT_MOUSE_SHOW: 1651 vw->vw_flags &= ~VWF_MOUSE_HIDE; 1652 break; 1653 } 1654 1655 /* Mark mouse position as dirty. */ 1656 vt_mark_mouse_position_as_dirty(vd); 1657 vt_resume_flush_timer(vw->vw_device, 0); 1658} 1659#endif 1660 1661static int 1662vtterm_mmap(struct terminal *tm, vm_ooffset_t offset, vm_paddr_t * paddr, 1663 int nprot, vm_memattr_t *memattr) 1664{ 1665 struct vt_window *vw = tm->tm_softc; 1666 struct vt_device *vd = vw->vw_device; 1667 1668 if (vd->vd_driver->vd_fb_mmap) 1669 return (vd->vd_driver->vd_fb_mmap(vd, offset, paddr, nprot, 1670 memattr)); 1671 1672 return (ENXIO); 1673} 1674 1675static int 1676vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1677 struct thread *td) 1678{ 1679 struct vt_window *vw = tm->tm_softc; 1680 struct vt_device *vd = vw->vw_device; 1681 keyboard_t *kbd; 1682 int error, i, s; 1683#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1684 defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1685 int ival; 1686 1687 switch (cmd) { 1688 case _IO('v', 4): 1689 cmd = VT_RELDISP; 1690 break; 1691 case _IO('v', 5): 1692 cmd = VT_ACTIVATE; 1693 break; 1694 case _IO('v', 6): 1695 cmd = VT_WAITACTIVE; 1696 break; 1697 case _IO('K', 20): 1698 cmd = KDSKBSTATE; 1699 break; 1700 case _IO('K', 67): 1701 cmd = KDSETRAD; 1702 break; 1703 case _IO('K', 7): 1704 cmd = KDSKBMODE; 1705 break; 1706 case _IO('K', 8): 1707 cmd = KDMKTONE; 1708 break; 1709 case _IO('K', 63): 1710 cmd = KIOCSOUND; 1711 break; 1712 case _IO('K', 66): 1713 cmd = KDSETLED; 1714 break; 1715 case _IO('c', 110): 1716 cmd = CONS_SETKBD; 1717 break; 1718 default: 1719 goto skip_thunk; 1720 } 1721 ival = IOCPARM_IVAL(data); 1722 data = (caddr_t)&ival; 1723skip_thunk: 1724#endif 1725 1726 switch (cmd) { 1727 case KDSETRAD: /* set keyboard repeat & delay rates (old) */ 1728 if (*(int *)data & ~0x7f) 1729 return (EINVAL); 1730 /* FALLTHROUGH */ 1731 case GIO_KEYMAP: 1732 case PIO_KEYMAP: 1733 case GIO_DEADKEYMAP: 1734 case PIO_DEADKEYMAP: 1735 case GETFKEY: 1736 case SETFKEY: 1737 case KDGKBINFO: 1738 case KDGKBTYPE: 1739 case KDSKBSTATE: /* set keyboard state (locks) */ 1740 case KDGKBSTATE: /* get keyboard state (locks) */ 1741 case KDGETREPEAT: /* get keyboard repeat & delay rates */ 1742 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ 1743 case KDSETLED: /* set keyboard LED status */ 1744 case KDGETLED: /* get keyboard LED status */ 1745 case KBADDKBD: /* add/remove keyboard to/from mux */ 1746 case KBRELKBD: { 1747 error = 0; 1748 1749 mtx_lock(&Giant); 1750 kbd = kbd_get_keyboard(vd->vd_keyboard); 1751 if (kbd != NULL) 1752 error = kbdd_ioctl(kbd, cmd, data); 1753 mtx_unlock(&Giant); 1754 if (error == ENOIOCTL) { 1755 if (cmd == KDGKBTYPE) { 1756 /* always return something? XXX */ 1757 *(int *)data = 0; 1758 } else { 1759 return (ENODEV); 1760 } 1761 } 1762 return (error); 1763 } 1764 case KDGKBMODE: { 1765 int mode = -1; 1766 1767 mtx_lock(&Giant); 1768 kbd = kbd_get_keyboard(vd->vd_keyboard); 1769 if (kbd != NULL) { 1770 kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1771 } 1772 mtx_unlock(&Giant); 1773 DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1774 *(int *)data = mode; 1775 return (0); 1776 } 1777 case KDSKBMODE: { 1778 int mode; 1779 1780 mode = *(int *)data; 1781 switch (mode) { 1782 case K_XLATE: 1783 case K_RAW: 1784 case K_CODE: 1785 vw->vw_kbdmode = mode; 1786 if (vw == vd->vd_curwindow) { 1787 keyboard_t *kbd; 1788 error = 0; 1789 1790 mtx_lock(&Giant); 1791 kbd = kbd_get_keyboard(vd->vd_keyboard); 1792 if (kbd != NULL) { 1793 error = kbdd_ioctl(kbd, KDSKBMODE, 1794 (void *)&mode); 1795 } 1796 mtx_unlock(&Giant); 1797 } 1798 return (0); 1799 default: 1800 return (EINVAL); 1801 } 1802 } 1803 case FBIOGTYPE: 1804 case FBIO_GETWINORG: /* get frame buffer window origin */ 1805 case FBIO_GETDISPSTART: /* get display start address */ 1806 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 1807 case FBIO_BLANK: /* blank display */ 1808 if (vd->vd_driver->vd_fb_ioctl) 1809 return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td)); 1810 break; 1811 case CONS_BLANKTIME: 1812 /* XXX */ 1813 return (0); 1814 case CONS_GET: 1815 /* XXX */ 1816 *(int *)data = M_CG640x480; 1817 return (0); 1818 case CONS_BELLTYPE: /* set bell type sound */ 1819 if ((*(int *)data) & CONS_QUIET_BELL) 1820 vd->vd_flags |= VDF_QUIET_BELL; 1821 else 1822 vd->vd_flags &= ~VDF_QUIET_BELL; 1823 return (0); 1824 case CONS_GETINFO: { 1825 vid_info_t *vi = (vid_info_t *)data; 1826 1827 vi->m_num = vd->vd_curwindow->vw_number + 1; 1828 /* XXX: other fields! */ 1829 return (0); 1830 } 1831 case CONS_GETVERS: 1832 *(int *)data = 0x200; 1833 return (0); 1834 case CONS_MODEINFO: 1835 /* XXX */ 1836 return (0); 1837 case CONS_MOUSECTL: { 1838 mouse_info_t *mouse = (mouse_info_t*)data; 1839 1840 /* 1841 * All the commands except MOUSE_SHOW nd MOUSE_HIDE 1842 * should not be applied to individual TTYs, but only to 1843 * consolectl. 1844 */ 1845 switch (mouse->operation) { 1846 case MOUSE_HIDE: 1847 if (vd->vd_flags & VDF_MOUSECURSOR) { 1848 vd->vd_flags &= ~VDF_MOUSECURSOR; 1849#ifndef SC_NO_CUTPASTE 1850 vt_mouse_state(VT_MOUSE_HIDE); 1851#endif 1852 } 1853 return (0); 1854 case MOUSE_SHOW: 1855 if (!(vd->vd_flags & VDF_MOUSECURSOR)) { 1856 vd->vd_flags |= VDF_MOUSECURSOR; 1857 vd->vd_mx = vd->vd_width / 2; 1858 vd->vd_my = vd->vd_height / 2; 1859#ifndef SC_NO_CUTPASTE 1860 vt_mouse_state(VT_MOUSE_SHOW); 1861#endif 1862 } 1863 return (0); 1864 default: 1865 return (EINVAL); 1866 } 1867 } 1868 case PIO_VFONT: { 1869 struct vt_font *vf; 1870 1871 error = vtfont_load((void *)data, &vf); 1872 if (error != 0) 1873 return (error); 1874 1875 error = vt_change_font(vw, vf); 1876 vtfont_unref(vf); 1877 return (error); 1878 } 1879 case GIO_SCRNMAP: { 1880 scrmap_t *sm = (scrmap_t *)data; 1881 1882 /* We don't have screen maps, so return a handcrafted one. */ 1883 for (i = 0; i < 256; i++) 1884 sm->scrmap[i] = i; 1885 return (0); 1886 } 1887 case KDSETMODE: 1888 /* 1889 * FIXME: This implementation is incomplete compared to 1890 * syscons. 1891 */ 1892 switch (*(int *)data) { 1893 case KD_TEXT: 1894 case KD_TEXT1: 1895 case KD_PIXEL: 1896 vw->vw_flags &= ~VWF_GRAPHICS; 1897 break; 1898 case KD_GRAPHICS: 1899 vw->vw_flags |= VWF_GRAPHICS; 1900 break; 1901 } 1902 return (0); 1903 case KDENABIO: /* allow io operations */ 1904 error = priv_check(td, PRIV_IO); 1905 if (error != 0) 1906 return (error); 1907 error = securelevel_gt(td->td_ucred, 0); 1908 if (error != 0) 1909 return (error); 1910#if defined(__i386__) 1911 td->td_frame->tf_eflags |= PSL_IOPL; 1912#elif defined(__amd64__) 1913 td->td_frame->tf_rflags |= PSL_IOPL; 1914#endif 1915 return (0); 1916 case KDDISABIO: /* disallow io operations (default) */ 1917#if defined(__i386__) 1918 td->td_frame->tf_eflags &= ~PSL_IOPL; 1919#elif defined(__amd64__) 1920 td->td_frame->tf_rflags &= ~PSL_IOPL; 1921#endif 1922 return (0); 1923 case KDMKTONE: /* sound the bell */ 1924 vtterm_beep(tm, *(u_int *)data); 1925 return (0); 1926 case KIOCSOUND: /* make tone (*data) hz */ 1927 /* TODO */ 1928 return (0); 1929 case CONS_SETKBD: /* set the new keyboard */ 1930 mtx_lock(&Giant); 1931 error = 0; 1932 if (vd->vd_keyboard != *(int *)data) { 1933 kbd = kbd_get_keyboard(*(int *)data); 1934 if (kbd == NULL) { 1935 mtx_unlock(&Giant); 1936 return (EINVAL); 1937 } 1938 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, 1939 (void *)vd, vt_kbdevent, vd); 1940 if (i >= 0) { 1941 if (vd->vd_keyboard != -1) { 1942 kbd_release(kbd, (void *)vd); 1943 } 1944 kbd = kbd_get_keyboard(i); 1945 vd->vd_keyboard = i; 1946 1947 (void)kbdd_ioctl(kbd, KDSKBMODE, 1948 (caddr_t)&vd->vd_curwindow->vw_kbdmode); 1949 } else { 1950 error = EPERM; /* XXX */ 1951 } 1952 } 1953 mtx_unlock(&Giant); 1954 return (error); 1955 case CONS_RELKBD: /* release the current keyboard */ 1956 mtx_lock(&Giant); 1957 error = 0; 1958 if (vd->vd_keyboard != -1) { 1959 kbd = kbd_get_keyboard(vd->vd_keyboard); 1960 if (kbd == NULL) { 1961 mtx_unlock(&Giant); 1962 return (EINVAL); 1963 } 1964 error = kbd_release(kbd, (void *)vd); 1965 if (error == 0) { 1966 vd->vd_keyboard = -1; 1967 } 1968 } 1969 mtx_unlock(&Giant); 1970 return (error); 1971 case VT_ACTIVATE: { 1972 int win; 1973 win = *(int *)data - 1; 1974 DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, 1975 VT_UNIT(vw), win); 1976 if ((win > VT_MAXWINDOWS) || (win < 0)) 1977 return (EINVAL); 1978 return (vt_proc_window_switch(vd->vd_windows[win])); 1979 } 1980 case VT_GETACTIVE: 1981 *(int *)data = vd->vd_curwindow->vw_number + 1; 1982 return (0); 1983 case VT_GETINDEX: 1984 *(int *)data = vw->vw_number + 1; 1985 return (0); 1986 case VT_LOCKSWITCH: 1987 /* TODO: Check current state, switching can be in progress. */ 1988 if ((*(int *)data) == 0x01) 1989 vw->vw_flags |= VWF_VTYLOCK; 1990 else if ((*(int *)data) == 0x02) 1991 vw->vw_flags &= ~VWF_VTYLOCK; 1992 else 1993 return (EINVAL); 1994 return (0); 1995 case VT_OPENQRY: 1996 VT_LOCK(vd); 1997 for (i = 0; i < VT_MAXWINDOWS; i++) { 1998 vw = vd->vd_windows[i]; 1999 if (vw == NULL) 2000 continue; 2001 if (!(vw->vw_flags & VWF_OPENED)) { 2002 *(int *)data = vw->vw_number + 1; 2003 VT_UNLOCK(vd); 2004 return (0); 2005 } 2006 } 2007 VT_UNLOCK(vd); 2008 return (EINVAL); 2009 case VT_WAITACTIVE: 2010 error = 0; 2011 2012 i = *(unsigned int *)data; 2013 if (i > VT_MAXWINDOWS) 2014 return (EINVAL); 2015 if (i != 0) 2016 vw = vd->vd_windows[i - 1]; 2017 2018 VT_LOCK(vd); 2019 while (vd->vd_curwindow != vw && error == 0) 2020 error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 2021 VT_UNLOCK(vd); 2022 return (error); 2023 case VT_SETMODE: { /* set screen switcher mode */ 2024 struct vt_mode *mode; 2025 struct proc *p1; 2026 2027 mode = (struct vt_mode *)data; 2028 DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 2029 if (vw->vw_smode.mode == VT_PROCESS) { 2030 p1 = pfind(vw->vw_pid); 2031 if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 2032 if (p1) 2033 PROC_UNLOCK(p1); 2034 DPRINTF(5, "error EPERM\n"); 2035 return (EPERM); 2036 } 2037 if (p1) 2038 PROC_UNLOCK(p1); 2039 } 2040 if (mode->mode == VT_AUTO) { 2041 vw->vw_smode.mode = VT_AUTO; 2042 vw->vw_proc = NULL; 2043 vw->vw_pid = 0; 2044 DPRINTF(5, "VT_AUTO, "); 2045 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 2046 cnavailable(vw->vw_terminal->consdev, TRUE); 2047 /* were we in the middle of the vty switching process? */ 2048 if (finish_vt_rel(vw, TRUE, &s) == 0) 2049 DPRINTF(5, "reset WAIT_REL, "); 2050 if (finish_vt_acq(vw) == 0) 2051 DPRINTF(5, "reset WAIT_ACQ, "); 2052 return (0); 2053 } else if (mode->mode == VT_PROCESS) { 2054 if (!ISSIGVALID(mode->relsig) || 2055 !ISSIGVALID(mode->acqsig) || 2056 !ISSIGVALID(mode->frsig)) { 2057 DPRINTF(5, "error EINVAL\n"); 2058 return (EINVAL); 2059 } 2060 DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 2061 bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 2062 vw->vw_proc = td->td_proc; 2063 vw->vw_pid = vw->vw_proc->p_pid; 2064 if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 2065 cnavailable(vw->vw_terminal->consdev, FALSE); 2066 } else { 2067 DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 2068 mode->mode); 2069 return (EINVAL); 2070 } 2071 DPRINTF(5, "\n"); 2072 return (0); 2073 } 2074 case VT_GETMODE: /* get screen switcher mode */ 2075 bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 2076 return (0); 2077 2078 case VT_RELDISP: /* screen switcher ioctl */ 2079 /* 2080 * This must be the current vty which is in the VT_PROCESS 2081 * switching mode... 2082 */ 2083 if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 2084 VT_PROCESS)) { 2085 return (EINVAL); 2086 } 2087 /* ...and this process is controlling it. */ 2088 if (vw->vw_proc != td->td_proc) { 2089 return (EPERM); 2090 } 2091 error = EINVAL; 2092 switch(*(int *)data) { 2093 case VT_FALSE: /* user refuses to release screen, abort */ 2094 if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 2095 DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", 2096 SC_DRIVER_NAME, VT_UNIT(vw)); 2097 break; 2098 case VT_TRUE: /* user has released screen, go on */ 2099 /* finish_vt_rel(..., TRUE, ...) should not be locked */ 2100 if (vw->vw_flags & VWF_SWWAIT_REL) { 2101 if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 2102 DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 2103 SC_DRIVER_NAME, VT_UNIT(vw)); 2104 } else { 2105 error = EINVAL; 2106 } 2107 return (error); 2108 case VT_ACKACQ: /* acquire acknowledged, switch completed */ 2109 if ((error = finish_vt_acq(vw)) == 0) 2110 DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", 2111 SC_DRIVER_NAME, VT_UNIT(vw)); 2112 break; 2113 default: 2114 break; 2115 } 2116 return (error); 2117 } 2118 2119 return (ENOIOCTL); 2120} 2121 2122static struct vt_window * 2123vt_allocate_window(struct vt_device *vd, unsigned int window) 2124{ 2125 struct vt_window *vw; 2126 struct terminal *tm; 2127 term_pos_t size; 2128 struct winsize wsz; 2129 2130 vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 2131 vw->vw_device = vd; 2132 vw->vw_number = window; 2133 vw->vw_kbdmode = K_XLATE; 2134 2135 if ((vd->vd_flags & VDF_TEXTMODE) == 0) { 2136 vw->vw_font = vtfont_ref(&vt_font_default); 2137 vt_compute_drawable_area(vw); 2138 } 2139 2140 vt_termsize(vd, vw->vw_font, &size); 2141 vt_winsize(vd, vw->vw_font, &wsz); 2142 vtbuf_init(&vw->vw_buf, &size); 2143 2144 tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 2145 terminal_set_winsize(tm, &wsz); 2146 vd->vd_windows[window] = vw; 2147 callout_init(&vw->vw_proc_dead_timer, 0); 2148 2149 return (vw); 2150} 2151 2152void 2153vt_upgrade(struct vt_device *vd) 2154{ 2155 struct vt_window *vw; 2156 unsigned int i; 2157 2158 if (!vty_enabled(VTY_VT)) 2159 return; 2160 2161 for (i = 0; i < VT_MAXWINDOWS; i++) { 2162 vw = vd->vd_windows[i]; 2163 if (vw == NULL) { 2164 /* New window. */ 2165 vw = vt_allocate_window(vd, i); 2166 } 2167 if (!(vw->vw_flags & VWF_READY)) { 2168 callout_init(&vw->vw_proc_dead_timer, 0); 2169 terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 2170 vw->vw_flags |= VWF_READY; 2171 if (vw->vw_flags & VWF_CONSOLE) { 2172 /* For existing console window. */ 2173 EVENTHANDLER_REGISTER(shutdown_pre_sync, 2174 vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 2175 } 2176 } 2177 2178 } 2179 VT_LOCK(vd); 2180 if (vd->vd_curwindow == NULL) 2181 vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 2182 2183 if (!(vd->vd_flags & VDF_ASYNC)) { 2184 /* Attach keyboard. */ 2185 vt_allocate_keyboard(vd); 2186 2187 /* Init 25 Hz timer. */ 2188 callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 2189 2190 /* Start timer when everything ready. */ 2191 vd->vd_flags |= VDF_ASYNC; 2192 callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 2193 vd->vd_timer_armed = 1; 2194 } 2195 2196 VT_UNLOCK(vd); 2197 2198 /* Refill settings with new sizes. */ 2199 vt_resize(vd); 2200} 2201 2202static void 2203vt_resize(struct vt_device *vd) 2204{ 2205 struct vt_window *vw; 2206 int i; 2207 2208 for (i = 0; i < VT_MAXWINDOWS; i++) { 2209 vw = vd->vd_windows[i]; 2210 VT_LOCK(vd); 2211 /* Assign default font to window, if not textmode. */ 2212 if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) 2213 vw->vw_font = vtfont_ref(&vt_font_default); 2214 VT_UNLOCK(vd); 2215 2216 /* Resize terminal windows */ 2217 while (vt_change_font(vw, vw->vw_font) == EBUSY) { 2218 DPRINTF(100, "%s: vt_change_font() is busy, " 2219 "window %d\n", __func__, i); 2220 } 2221 } 2222} 2223 2224void 2225vt_allocate(struct vt_driver *drv, void *softc) 2226{ 2227 struct vt_device *vd; 2228 2229 if (!vty_enabled(VTY_VT)) 2230 return; 2231 2232 if (main_vd->vd_driver == NULL) { 2233 main_vd->vd_driver = drv; 2234 printf("VT: initialize with new VT driver \"%s\".\n", 2235 drv->vd_name); 2236 } else { 2237 /* 2238 * Check if have rights to replace current driver. For example: 2239 * it is bad idea to replace KMS driver with generic VGA one. 2240 */ 2241 if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 2242 printf("VT: Driver priority %d too low. Current %d\n ", 2243 drv->vd_priority, main_vd->vd_driver->vd_priority); 2244 return; 2245 } 2246 printf("VT: Replacing driver \"%s\" with new \"%s\".\n", 2247 main_vd->vd_driver->vd_name, drv->vd_name); 2248 } 2249 vd = main_vd; 2250 VT_LOCK(vd); 2251 2252 if (vd->vd_flags & VDF_ASYNC) { 2253 /* Stop vt_flush periodic task. */ 2254 vt_suspend_flush_timer(vd); 2255 /* 2256 * Mute current terminal until we done. vt_change_font (called 2257 * from vt_resize) will unmute it. 2258 */ 2259 terminal_mute(vd->vd_curwindow->vw_terminal, 1); 2260 } 2261 2262 /* 2263 * Reset VDF_TEXTMODE flag, driver who require that flag (vt_vga) will 2264 * set it. 2265 */ 2266 vd->vd_flags &= ~VDF_TEXTMODE; 2267 2268 vd->vd_driver = drv; 2269 vd->vd_softc = softc; 2270 vd->vd_driver->vd_init(vd); 2271 VT_UNLOCK(vd); 2272 2273 /* Update windows sizes and initialize last items. */ 2274 vt_upgrade(vd); 2275 2276#ifdef DEV_SPLASH 2277 if (vd->vd_flags & VDF_SPLASH) 2278 vtterm_splash(vd); 2279#endif 2280 2281 if (vd->vd_flags & VDF_ASYNC) { 2282 /* Allow to put chars now. */ 2283 terminal_mute(vd->vd_curwindow->vw_terminal, 0); 2284 /* Rerun timer for screen updates. */ 2285 vt_resume_flush_timer(vd, 0); 2286 } 2287 2288 /* 2289 * Register as console. If it already registered, cnadd() will ignore 2290 * it. 2291 */ 2292 termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 2293} 2294 2295void 2296vt_suspend() 2297{ 2298 2299 if (vt_suspendswitch == 0) 2300 return; 2301 /* Save current window. */ 2302 main_vd->vd_savedwindow = main_vd->vd_curwindow; 2303 /* Ask holding process to free window and switch to console window */ 2304 vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]); 2305} 2306 2307void 2308vt_resume() 2309{ 2310 2311 if (vt_suspendswitch == 0) 2312 return; 2313 /* Switch back to saved window */ 2314 if (main_vd->vd_savedwindow != NULL) 2315 vt_proc_window_switch(main_vd->vd_savedwindow); 2316 main_vd->vd_savedwindow = NULL; 2317} 2318