vt_core.c revision 258023
1219888Sed/*- 2257547Sray * Copyright (c) 2009, 2013 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8257547Sray * Portions of this software were developed by Oleksandr Rybalko 9257547Sray * under sponsorship from the FreeBSD Foundation. 10257547Sray * 11219888Sed * Redistribution and use in source and binary forms, with or without 12219888Sed * modification, are permitted provided that the following conditions 13219888Sed * are met: 14219888Sed * 1. Redistributions of source code must retain the above copyright 15219888Sed * notice, this list of conditions and the following disclaimer. 16219888Sed * 2. Redistributions in binary form must reproduce the above copyright 17219888Sed * notice, this list of conditions and the following disclaimer in the 18219888Sed * documentation and/or other materials provided with the distribution. 19219888Sed * 20219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30219888Sed * SUCH DAMAGE. 31219888Sed */ 32219888Sed 33219888Sed#include <sys/cdefs.h> 34219888Sed__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/vt_core.c 258023 2013-11-11 22:07:56Z ray $"); 35219888Sed 36219888Sed#include <sys/param.h> 37219888Sed#include <sys/consio.h> 38219888Sed#include <sys/eventhandler.h> 39219888Sed#include <sys/fbio.h> 40219888Sed#include <sys/kbio.h> 41219888Sed#include <sys/kdb.h> 42219888Sed#include <sys/kernel.h> 43219888Sed#include <sys/lock.h> 44219888Sed#include <sys/malloc.h> 45219888Sed#include <sys/mutex.h> 46256145Sray#include <sys/proc.h> 47219888Sed#include <sys/reboot.h> 48219888Sed#include <sys/systm.h> 49219888Sed#include <sys/terminal.h> 50219888Sed 51219888Sed#include <dev/kbd/kbdreg.h> 52219888Sed#include <dev/vt/vt.h> 53219888Sed 54219888Sedstatic tc_bell_t vtterm_bell; 55219888Sedstatic tc_cursor_t vtterm_cursor; 56219888Sedstatic tc_putchar_t vtterm_putchar; 57219888Sedstatic tc_fill_t vtterm_fill; 58219888Sedstatic tc_copy_t vtterm_copy; 59219888Sedstatic tc_param_t vtterm_param; 60219888Sedstatic tc_done_t vtterm_done; 61219888Sed 62219888Sedstatic tc_cnprobe_t vtterm_cnprobe; 63219888Sedstatic tc_cngetc_t vtterm_cngetc; 64219888Sed 65219888Sedstatic tc_opened_t vtterm_opened; 66219888Sedstatic tc_ioctl_t vtterm_ioctl; 67219888Sed 68219888Sedconst struct terminal_class vt_termclass = { 69219888Sed .tc_bell = vtterm_bell, 70219888Sed .tc_cursor = vtterm_cursor, 71219888Sed .tc_putchar = vtterm_putchar, 72219888Sed .tc_fill = vtterm_fill, 73219888Sed .tc_copy = vtterm_copy, 74219888Sed .tc_param = vtterm_param, 75219888Sed .tc_done = vtterm_done, 76219888Sed 77219888Sed .tc_cnprobe = vtterm_cnprobe, 78219888Sed .tc_cngetc = vtterm_cngetc, 79219888Sed 80219888Sed .tc_opened = vtterm_opened, 81219888Sed .tc_ioctl = vtterm_ioctl, 82219888Sed}; 83219888Sed 84219888Sed/* 85257296Snwhitehorn * Use a constant timer of 25 Hz to redraw the screen. 86219888Sed * 87219888Sed * XXX: In theory we should only fire up the timer when there is really 88219888Sed * activity. Unfortunately we cannot always start timers. We really 89219888Sed * don't want to process kernel messages synchronously, because it 90219888Sed * really slows down the system. 91219888Sed */ 92257296Snwhitehorn#define VT_TIMERFREQ 25 93219888Sed 94219888Sed/* Bell pitch/duration. */ 95219888Sed#define VT_BELLDURATION ((5 * hz + 99) / 100) 96219888Sed#define VT_BELLPITCH 800 97219888Sed 98219888Sed#define VT_LOCK(vd) mtx_lock(&(vd)->vd_lock) 99219888Sed#define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) 100219888Sed 101219888Sed#define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \ 102219888Sed (vw)->vw_number) 103219888Sed 104256145Sray/* XXX while syscons is here. */ 105256145Srayint sc_txtmouse_no_retrace_wait; 106256145Sray 107256145Sraystatic SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters"); 108256145SrayVT_SYSCTL_INT(debug, 0, "Newcons debug level"); 109256145SrayVT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); 110258023SrayVT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend"); 111256145Sray 112219888Sedstatic unsigned int vt_unit = 0; 113219888Sedstatic MALLOC_DEFINE(M_VT, "vt", "vt device"); 114256145Sraystruct vt_device *main_vd = NULL; 115219888Sed 116219888Sed/* Boot logo. */ 117219888Sedextern unsigned int vt_logo_width; 118219888Sedextern unsigned int vt_logo_height; 119219888Sedextern unsigned int vt_logo_depth; 120219888Sedextern unsigned char vt_logo_image[]; 121219888Sed 122219888Sed/* Font. */ 123219888Sedextern struct vt_font vt_font_default; 124257986Srayextern struct mouse_cursor vt_default_mouse_pointer; 125219888Sed 126256145Sraystatic int signal_vt_rel(struct vt_window *); 127256145Sraystatic int signal_vt_acq(struct vt_window *); 128256145Sraystatic int finish_vt_rel(struct vt_window *, int, int *); 129256145Sraystatic int finish_vt_acq(struct vt_window *); 130256145Sraystatic int vt_window_switch(struct vt_window *); 131256145Sraystatic int vt_late_window_switch(struct vt_window *); 132256145Sraystatic int vt_proc_alive(struct vt_window *); 133256145Sraystatic void vt_resize(struct vt_device *); 134256145Sray 135219888Sedstatic void 136256145Srayvt_switch_timer(void *arg) 137256145Sray{ 138256145Sray 139256145Sray vt_late_window_switch((struct vt_window *)arg); 140256145Sray} 141256145Sray 142256145Sraystatic int 143256145Srayvt_window_preswitch(struct vt_window *vw, struct vt_window *curvw) 144256145Sray{ 145256145Sray 146256145Sray DPRINTF(40, "%s\n", __func__); 147256145Sray curvw->vw_switch_to = vw; 148256145Sray /* Set timer to allow switch in case when process hang. */ 149256145Sray callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer, 150256145Sray vt_switch_timer, (void *)vw); 151256145Sray /* Notify process about vt switch attempt. */ 152256145Sray DPRINTF(30, "%s: Notify process.\n", __func__); 153256145Sray signal_vt_rel(curvw); 154256145Sray 155256145Sray return (0); 156256145Sray} 157256145Sray 158256145Sraystatic int 159256145Srayvt_window_postswitch(struct vt_window *vw) 160256145Sray{ 161256145Sray 162256145Sray signal_vt_acq(vw); 163256145Sray return (0); 164256145Sray} 165256145Sray 166256145Sray/* vt_late_window_switch will done VT switching for regular case. */ 167256145Sraystatic int 168256145Srayvt_late_window_switch(struct vt_window *vw) 169256145Sray{ 170256145Sray int ret; 171256145Sray 172256145Sray callout_stop(&vw->vw_proc_dead_timer); 173256145Sray 174256145Sray ret = vt_window_switch(vw); 175256145Sray if (ret) 176256145Sray return (ret); 177256145Sray 178256145Sray /* Notify owner process about terminal availability. */ 179256145Sray if (vw->vw_smode.mode == VT_PROCESS) { 180256145Sray ret = vt_window_postswitch(vw); 181256145Sray } 182256145Sray return (ret); 183256145Sray} 184256145Sray 185256145Sray/* Switch window. */ 186256145Sraystatic int 187256145Srayvt_proc_window_switch(struct vt_window *vw) 188256145Sray{ 189256145Sray struct vt_window *curvw; 190256145Sray struct vt_device *vd; 191256145Sray int ret; 192256145Sray 193256145Sray if (vw->vw_flags & VWF_VTYLOCK) 194256145Sray return (EBUSY); 195256145Sray 196256145Sray vd = vw->vw_device; 197256145Sray curvw = vd->vd_curwindow; 198256145Sray 199256145Sray /* Ask current process permitions to switch away. */ 200256145Sray if (curvw->vw_smode.mode == VT_PROCESS) { 201256145Sray DPRINTF(30, "%s: VT_PROCESS ", __func__); 202256145Sray if (vt_proc_alive(curvw) == FALSE) { 203256145Sray DPRINTF(30, "Dead. Cleaning."); 204256145Sray /* Dead */ 205256145Sray } else { 206256145Sray DPRINTF(30, "%s: Signaling process.\n", __func__); 207256145Sray /* Alive, try to ask him. */ 208256145Sray ret = vt_window_preswitch(vw, curvw); 209256145Sray /* Wait for process answer or timeout. */ 210256145Sray return (ret); 211256145Sray } 212256145Sray DPRINTF(30, "\n"); 213256145Sray } 214256145Sray 215256145Sray ret = vt_late_window_switch(vw); 216256145Sray return (ret); 217256145Sray} 218256145Sray 219256145Sray/* Switch window ignoring process locking. */ 220256145Sraystatic int 221219888Sedvt_window_switch(struct vt_window *vw) 222219888Sed{ 223219888Sed struct vt_device *vd = vw->vw_device; 224256145Sray struct vt_window *curvw = vd->vd_curwindow; 225219888Sed keyboard_t *kbd; 226219888Sed 227219888Sed VT_LOCK(vd); 228256145Sray if (curvw == vw) { 229256145Sray /* Nothing to do. */ 230219888Sed VT_UNLOCK(vd); 231256145Sray return (0); 232219888Sed } 233256145Sray if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 234256145Sray VT_UNLOCK(vd); 235256145Sray return (EINVAL); 236256145Sray } 237256145Sray 238219888Sed vd->vd_curwindow = vw; 239219888Sed vd->vd_flags |= VDF_INVALID; 240219888Sed cv_broadcast(&vd->vd_winswitch); 241219888Sed VT_UNLOCK(vd); 242219888Sed 243256145Sray if (vd->vd_driver->vd_postswitch) 244256145Sray vd->vd_driver->vd_postswitch(vd); 245256145Sray 246219888Sed /* Restore per-window keyboard mode. */ 247219888Sed mtx_lock(&Giant); 248219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 249256145Sray if (kbd != NULL) { 250219888Sed kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode); 251256145Sray } 252219888Sed mtx_unlock(&Giant); 253256145Sray DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number); 254256145Sray 255256145Sray return (0); 256219888Sed} 257219888Sed 258219888Sedstatic inline void 259219888Sedvt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size) 260219888Sed{ 261219888Sed 262219888Sed size->tp_row = vd->vd_height; 263219888Sed size->tp_col = vd->vd_width; 264219888Sed if (vf != NULL) { 265219888Sed size->tp_row /= vf->vf_height; 266219888Sed size->tp_col /= vf->vf_width; 267219888Sed } 268219888Sed} 269219888Sed 270219888Sedstatic inline void 271219888Sedvt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size) 272219888Sed{ 273219888Sed 274219888Sed size->ws_row = size->ws_ypixel = vd->vd_height; 275219888Sed size->ws_col = size->ws_xpixel = vd->vd_width; 276219888Sed if (vf != NULL) { 277219888Sed size->ws_row /= vf->vf_height; 278219888Sed size->ws_col /= vf->vf_width; 279219888Sed } 280219888Sed} 281219888Sed 282257076Sraystatic void 283257076Srayvt_scroll(struct vt_window *vw, int offset, int whence) 284257076Sray{ 285257076Sray int diff; 286257076Sray term_pos_t size; 287257076Sray 288257076Sray if ((vw->vw_flags & VWF_SCROLL) == 0) 289257076Sray return; 290257076Sray 291257076Sray vt_termsize(vw->vw_device, vw->vw_font, &size); 292257076Sray 293257076Sray diff = vthistory_seek(&vw->vw_buf, offset, whence); 294257076Sray /* 295257076Sray * Offset changed, please update Nth lines on sceen. 296257076Sray * +N - Nth lines at top; 297257076Sray * -N - Nth lines at bottom. 298257076Sray */ 299257076Sray 300257076Sray if (diff < -size.tp_row || diff > size.tp_row) { 301257076Sray vw->vw_device->vd_flags |= VDF_INVALID; 302257076Sray return; 303257076Sray } 304257076Sray vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/ 305257076Sray} 306257076Sray 307219888Sedstatic int 308257076Srayvt_machine_kbdevent(int c) 309257076Sray{ 310257076Sray 311257076Sray switch (c) { 312257076Sray case SPCLKEY | DBG: 313257076Sray kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 314257076Sray return (1); 315257076Sray case SPCLKEY | RBT: 316257076Sray /* XXX: Make this configurable! */ 317257076Sray shutdown_nice(0); 318257076Sray return (1); 319257076Sray case SPCLKEY | HALT: 320257076Sray shutdown_nice(RB_HALT); 321257076Sray return (1); 322257076Sray case SPCLKEY | PDWN: 323257076Sray shutdown_nice(RB_HALT|RB_POWEROFF); 324257076Sray return (1); 325257076Sray }; 326257076Sray 327257076Sray return (0); 328257076Sray} 329257076Sray 330257076Sraystatic void 331257076Srayvt_scrollmode_kbdevent(struct vt_window *vw, int c, int console) 332257076Sray{ 333257076Sray struct vt_device *vd; 334257076Sray term_pos_t size; 335257076Sray 336257076Sray vd = vw->vw_device; 337257076Sray /* Only special keys handled in ScrollLock mode */ 338257076Sray if ((c & SPCLKEY) == 0) 339257076Sray return; 340257076Sray 341257076Sray c &= ~SPCLKEY; 342257076Sray 343257076Sray if (console == 0) { 344257076Sray if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 345257076Sray vw = vd->vd_windows[c - F_SCR]; 346257076Sray if (vw != NULL) 347257076Sray vt_proc_window_switch(vw); 348257076Sray return; 349257076Sray } 350257076Sray VT_LOCK(vd); 351257076Sray } 352257076Sray 353257076Sray switch (c) { 354257076Sray case SLK: { 355257076Sray /* Turn scrolling off. */ 356257076Sray vt_scroll(vw, 0, VHS_END); 357257076Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 358257076Sray vw->vw_flags &= ~VWF_SCROLL; 359257076Sray break; 360257076Sray } 361257076Sray case FKEY | F(49): /* Home key. */ 362257076Sray vt_scroll(vw, 0, VHS_END); 363257076Sray break; 364257076Sray case FKEY | F(50): /* Arrow up. */ 365257076Sray vt_scroll(vw, -1, VHS_CUR); 366257076Sray break; 367257076Sray case FKEY | F(51): /* Page up. */ 368257076Sray vt_termsize(vd, vw->vw_font, &size); 369257076Sray vt_scroll(vw, -size.tp_row, VHS_CUR); 370257076Sray break; 371257076Sray case FKEY | F(57): /* End key. */ 372257076Sray vt_scroll(vw, 0, VHS_SET); 373257076Sray break; 374257076Sray case FKEY | F(58): /* Arrow down. */ 375257076Sray vt_scroll(vw, 1, VHS_CUR); 376257076Sray break; 377257076Sray case FKEY | F(59): /* Page down. */ 378257076Sray vt_termsize(vd, vw->vw_font, &size); 379257076Sray vt_scroll(vw, size.tp_row, VHS_CUR); 380257076Sray break; 381257076Sray } 382257076Sray 383257076Sray if (console == 0) 384257076Sray VT_UNLOCK(vd); 385257076Sray} 386257076Sray 387257076Sraystatic int 388257294Snwhitehornvt_processkey(keyboard_t *kbd, struct vt_device *vd, int c) 389219888Sed{ 390219888Sed struct vt_window *vw = vd->vd_curwindow; 391257294Snwhitehorn int state = 0; 392219888Sed 393219888Sed if (c & RELKEY) 394219888Sed return (0); 395219888Sed 396257076Sray if (vt_machine_kbdevent(c)) 397257076Sray return (0); 398257076Sray 399257076Sray if (vw->vw_flags & VWF_SCROLL) { 400257076Sray vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 401257076Sray /* Scroll mode keys handled, nothing to do more. */ 402257076Sray return (0); 403257076Sray } 404257076Sray 405219888Sed if (c & SPCLKEY) { 406219888Sed c &= ~SPCLKEY; 407219888Sed 408219888Sed if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 409219888Sed vw = vd->vd_windows[c - F_SCR]; 410219888Sed if (vw != NULL) 411256145Sray vt_proc_window_switch(vw); 412219888Sed return (0); 413219888Sed } 414219888Sed 415219888Sed switch (c) { 416219888Sed case SLK: { 417219888Sed 418219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 419219888Sed VT_LOCK(vd); 420219888Sed if (state & SLKED) { 421219888Sed /* Turn scrolling on. */ 422219888Sed vw->vw_flags |= VWF_SCROLL; 423256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 424219888Sed } else { 425219888Sed /* Turn scrolling off. */ 426219888Sed vw->vw_flags &= ~VWF_SCROLL; 427256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 428257076Sray vt_scroll(vw, 0, VHS_END); 429219888Sed } 430219888Sed VT_UNLOCK(vd); 431219888Sed break; 432219888Sed } 433219888Sed case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 434219888Sed case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 435219888Sed case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 436219888Sed case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 437219888Sed /* F1 through F12 keys. */ 438219888Sed terminal_input_special(vw->vw_terminal, 439219888Sed TKEY_F1 + c - (FKEY | F(1))); 440219888Sed break; 441219888Sed case FKEY | F(49): /* Home key. */ 442219888Sed terminal_input_special(vw->vw_terminal, TKEY_HOME); 443219888Sed break; 444219888Sed case FKEY | F(50): /* Arrow up. */ 445219888Sed terminal_input_special(vw->vw_terminal, TKEY_UP); 446219888Sed break; 447219888Sed case FKEY | F(51): /* Page up. */ 448219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 449219888Sed break; 450219888Sed case FKEY | F(53): /* Arrow left. */ 451219888Sed terminal_input_special(vw->vw_terminal, TKEY_LEFT); 452219888Sed break; 453219888Sed case FKEY | F(55): /* Arrow right. */ 454219888Sed terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 455219888Sed break; 456219888Sed case FKEY | F(57): /* End key. */ 457219888Sed terminal_input_special(vw->vw_terminal, TKEY_END); 458219888Sed break; 459219888Sed case FKEY | F(58): /* Arrow down. */ 460219888Sed terminal_input_special(vw->vw_terminal, TKEY_DOWN); 461219888Sed break; 462219888Sed case FKEY | F(59): /* Page down. */ 463219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 464219888Sed break; 465219888Sed case FKEY | F(60): /* Insert key. */ 466219888Sed terminal_input_special(vw->vw_terminal, TKEY_INSERT); 467219888Sed break; 468219888Sed case FKEY | F(61): /* Delete key. */ 469219888Sed terminal_input_special(vw->vw_terminal, TKEY_DELETE); 470219888Sed break; 471219888Sed } 472219888Sed } else if (KEYFLAGS(c) == 0) { 473219888Sed /* Don't do UTF-8 conversion when doing raw mode. */ 474219888Sed if (vw->vw_kbdmode == K_XLATE) 475256145Sray terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 476219888Sed else 477219888Sed terminal_input_raw(vw->vw_terminal, c); 478219888Sed } 479219888Sed return (0); 480219888Sed} 481219888Sed 482219888Sedstatic int 483257294Snwhitehornvt_kbdevent(keyboard_t *kbd, int event, void *arg) 484257294Snwhitehorn{ 485257294Snwhitehorn struct vt_device *vd = arg; 486257294Snwhitehorn int c; 487257294Snwhitehorn 488257294Snwhitehorn switch (event) { 489257294Snwhitehorn case KBDIO_KEYINPUT: 490257294Snwhitehorn break; 491257294Snwhitehorn case KBDIO_UNLOADING: 492257294Snwhitehorn mtx_lock(&Giant); 493257294Snwhitehorn vd->vd_keyboard = -1; 494257294Snwhitehorn kbd_release(kbd, (void *)&vd->vd_keyboard); 495257294Snwhitehorn mtx_unlock(&Giant); 496257294Snwhitehorn return (0); 497257294Snwhitehorn default: 498257294Snwhitehorn return (EINVAL); 499257294Snwhitehorn } 500257294Snwhitehorn 501257294Snwhitehorn while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 502257294Snwhitehorn vt_processkey(kbd, vd, c); 503257294Snwhitehorn 504257294Snwhitehorn return (0); 505257294Snwhitehorn} 506257294Snwhitehorn 507257294Snwhitehornstatic int 508219888Sedvt_allocate_keyboard(struct vt_device *vd) 509219888Sed{ 510219888Sed int idx0, idx; 511219888Sed keyboard_t *k0, *k; 512219888Sed keyboard_info_t ki; 513219888Sed 514219888Sed idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard, 515219888Sed vt_kbdevent, vd); 516256145Sray /* XXX: kb_token lost */ 517256145Sray vd->vd_keyboard = idx0; 518219888Sed if (idx0 != -1) { 519256145Sray DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 520219888Sed k0 = kbd_get_keyboard(idx0); 521219888Sed 522219888Sed for (idx = kbd_find_keyboard2("*", -1, 0); 523219888Sed idx != -1; 524219888Sed idx = kbd_find_keyboard2("*", -1, idx + 1)) { 525219888Sed k = kbd_get_keyboard(idx); 526219888Sed 527219888Sed if (idx == idx0 || KBD_IS_BUSY(k)) 528219888Sed continue; 529219888Sed 530219888Sed bzero(&ki, sizeof(ki)); 531219888Sed strcpy(ki.kb_name, k->kb_name); 532219888Sed ki.kb_unit = k->kb_unit; 533219888Sed 534219888Sed kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 535219888Sed } 536256145Sray } else { 537256145Sray DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 538219888Sed idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard, 539219888Sed vt_kbdevent, vd); 540256145Sray } 541256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 542219888Sed 543219888Sed return (idx0); 544219888Sed} 545219888Sed 546219888Sedstatic void 547219888Sedvtterm_bell(struct terminal *tm) 548219888Sed{ 549219888Sed 550219888Sed sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION); 551219888Sed} 552219888Sed 553219888Sedstatic void 554219888Sedvtterm_cursor(struct terminal *tm, const term_pos_t *p) 555219888Sed{ 556219888Sed struct vt_window *vw = tm->tm_softc; 557219888Sed 558219888Sed vtbuf_cursor_position(&vw->vw_buf, p); 559219888Sed} 560219888Sed 561219888Sedstatic void 562219888Sedvtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 563219888Sed{ 564219888Sed struct vt_window *vw = tm->tm_softc; 565219888Sed 566219888Sed vtbuf_putchar(&vw->vw_buf, p, c); 567219888Sed} 568219888Sed 569219888Sedstatic void 570219888Sedvtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 571219888Sed{ 572219888Sed struct vt_window *vw = tm->tm_softc; 573219888Sed 574256145Sray vtbuf_fill_locked(&vw->vw_buf, r, c); 575219888Sed} 576219888Sed 577219888Sedstatic void 578219888Sedvtterm_copy(struct terminal *tm, const term_rect_t *r, 579219888Sed const term_pos_t *p) 580219888Sed{ 581219888Sed struct vt_window *vw = tm->tm_softc; 582219888Sed 583219888Sed vtbuf_copy(&vw->vw_buf, r, p); 584219888Sed} 585219888Sed 586219888Sedstatic void 587219888Sedvtterm_param(struct terminal *tm, int cmd, unsigned int arg) 588219888Sed{ 589219888Sed struct vt_window *vw = tm->tm_softc; 590219888Sed 591219888Sed switch (cmd) { 592219888Sed case TP_SHOWCURSOR: 593219888Sed vtbuf_cursor_visibility(&vw->vw_buf, arg); 594219888Sed break; 595219888Sed } 596219888Sed} 597219888Sed 598219888Sedstatic inline void 599219888Sedvt_determine_colors(term_char_t c, int cursor, 600219888Sed term_color_t *fg, term_color_t *bg) 601219888Sed{ 602219888Sed 603219888Sed *fg = TCHAR_FGCOLOR(c); 604219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) 605219888Sed *fg = TCOLOR_LIGHT(*fg); 606219888Sed *bg = TCHAR_BGCOLOR(c); 607219888Sed 608219888Sed if (TCHAR_FORMAT(c) & TF_REVERSE) { 609219888Sed term_color_t tmp; 610219888Sed 611219888Sed tmp = *fg; 612219888Sed *fg = *bg; 613219888Sed *bg = tmp; 614219888Sed } 615219888Sed 616219888Sed if (cursor) { 617219888Sed *fg = *bg; 618219888Sed *bg = TC_WHITE; 619219888Sed } 620219888Sed} 621219888Sed 622219888Sedstatic void 623219888Sedvt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c, 624219888Sed int iscursor, unsigned int row, unsigned int col) 625219888Sed{ 626219888Sed term_color_t fg, bg; 627219888Sed 628219888Sed vt_determine_colors(c, iscursor, &fg, &bg); 629219888Sed 630219888Sed if (vf != NULL) { 631219888Sed const uint8_t *src; 632219888Sed vt_axis_t top, left; 633219888Sed 634219888Sed src = vtfont_lookup(vf, c); 635219888Sed 636219888Sed /* 637219888Sed * Align the terminal to the centre of the screen. 638219888Sed * Fonts may not always be able to fill the entire 639219888Sed * screen. 640219888Sed */ 641257979Sray top = row * vf->vf_height + vd->vd_offset.tp_row; 642257979Sray left = col * vf->vf_width + vd->vd_offset.tp_col; 643219888Sed 644257988Sray vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left, 645219888Sed vf->vf_width, vf->vf_height, fg, bg); 646219888Sed } else { 647219888Sed vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c), 648219888Sed row, col, fg, bg); 649219888Sed } 650219888Sed} 651219888Sed 652219888Sedstatic void 653219888Sedvt_flush(struct vt_device *vd) 654219888Sed{ 655219888Sed struct vt_window *vw = vd->vd_curwindow; 656219888Sed struct vt_font *vf = vw->vw_font; 657219888Sed struct vt_bufmask tmask; 658257981Sray struct mouse_cursor *m; 659256145Sray unsigned int row, col; 660257981Sray term_rect_t tarea; 661257981Sray term_pos_t size; 662256145Sray term_char_t *r; 663257988Sray int bpl, h, w; 664219888Sed 665219888Sed if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY) 666219888Sed return; 667219888Sed 668219888Sed vtbuf_undirty(&vw->vw_buf, &tarea, &tmask); 669219888Sed vt_termsize(vd, vf, &size); 670219888Sed 671219888Sed /* Force a full redraw when the screen contents are invalid. */ 672256145Sray if (vd->vd_flags & VDF_INVALID) { 673219888Sed tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0; 674219888Sed tarea.tr_end = size; 675219888Sed tmask.vbm_row = tmask.vbm_col = VBM_DIRTY; 676219888Sed 677219888Sed vd->vd_flags &= ~VDF_INVALID; 678219888Sed } 679219888Sed 680257981Sray /* No mouse for DDB. */ 681257981Sray if (kdb_active || panicstr != NULL) 682257981Sray return; 683219888Sed 684257981Sray /* Mark last mouse position as dirty to erase. */ 685257981Sray vtbuf_mouse_cursor_position(&vw->vw_buf, vd->vd_mdirtyx, vd->vd_mdirtyy); 686257981Sray 687219888Sed for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) { 688219888Sed if (!VTBUF_DIRTYROW(&tmask, row)) 689219888Sed continue; 690256145Sray r = VTBUF_GET_ROW(&vw->vw_buf, row); 691219888Sed for (col = tarea.tr_begin.tp_col; 692219888Sed col < tarea.tr_end.tp_col; col++) { 693219888Sed if (!VTBUF_DIRTYCOL(&tmask, col)) 694219888Sed continue; 695219888Sed 696256145Sray vt_bitblt_char(vd, vf, r[col], 697256903Sray VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col); 698219888Sed } 699219888Sed } 700257981Sray 701257981Sray if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) == 702257981Sray VDF_MOUSECURSOR) { 703257981Sray m = &vt_default_mouse_pointer; 704257988Sray bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */ 705257981Sray w = m->w; 706257981Sray h = m->h; 707257981Sray 708257981Sray if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width)) 709257981Sray w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1; 710257981Sray if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height)) 711257981Sray h = (size.tp_row * vf->vf_height) - vd->vd_my - 1; 712257981Sray 713257988Sray vd->vd_driver->vd_bitbltchr(vd, m->map, m->mask, bpl, 714257981Sray vd->vd_offset.tp_row + vd->vd_my, 715257981Sray vd->vd_offset.tp_col + vd->vd_mx, 716257981Sray w, h, TC_WHITE, TC_BLACK); 717257981Sray /* Save point of last mouse cursor to erase it later. */ 718257981Sray vd->vd_mdirtyx = vd->vd_mx / vf->vf_width; 719257981Sray vd->vd_mdirtyy = vd->vd_my / vf->vf_height; 720257981Sray } 721219888Sed} 722219888Sed 723219888Sedstatic void 724219888Sedvt_timer(void *arg) 725219888Sed{ 726257387Sray struct vt_device *vd; 727219888Sed 728257387Sray vd = arg; 729257387Sray /* Update screen if required. */ 730219888Sed vt_flush(vd); 731257387Sray /* Schedule for next update. */ 732219888Sed callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 733219888Sed} 734219888Sed 735219888Sedstatic void 736219888Sedvtterm_done(struct terminal *tm) 737219888Sed{ 738219888Sed struct vt_window *vw = tm->tm_softc; 739219888Sed struct vt_device *vd = vw->vw_device; 740219888Sed 741219888Sed if (kdb_active || panicstr != NULL) { 742219888Sed /* Switch to the debugger. */ 743219888Sed if (vd->vd_curwindow != vw) { 744219888Sed vd->vd_curwindow = vw; 745219888Sed vd->vd_flags |= VDF_INVALID; 746257626Sray if (vd->vd_driver->vd_postswitch) 747257626Sray vd->vd_driver->vd_postswitch(vd); 748219888Sed } 749219888Sed vd->vd_flags &= ~VDF_SPLASH; 750219888Sed vt_flush(vd); 751219888Sed } else if (!(vd->vd_flags & VDF_ASYNC)) { 752219888Sed vt_flush(vd); 753219888Sed } 754219888Sed} 755219888Sed 756219888Sedstatic void 757256145Srayvtterm_splash(struct vt_device *vd) 758256145Sray{ 759256145Sray vt_axis_t top, left; 760256145Sray 761256145Sray /* Display a nice boot splash. */ 762257722Sray if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) { 763256145Sray 764256145Sray top = (vd->vd_height - vt_logo_height) / 2; 765256145Sray left = (vd->vd_width - vt_logo_width) / 2; 766256145Sray switch (vt_logo_depth) { 767256145Sray case 1: 768256145Sray /* XXX: Unhardcode colors! */ 769257988Sray vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0, 770257988Sray top, left, vt_logo_width, vt_logo_height, 0xf, 0x0); 771256145Sray } 772256145Sray vd->vd_flags |= VDF_SPLASH; 773256145Sray } 774256145Sray} 775256145Sray 776256145Sraystatic void 777219888Sedvtterm_cnprobe(struct terminal *tm, struct consdev *cp) 778219888Sed{ 779219888Sed struct vt_window *vw = tm->tm_softc; 780219888Sed struct vt_device *vd = vw->vw_device; 781219888Sed struct winsize wsz; 782219888Sed 783256145Sray if (vd->vd_flags & VDF_INITIALIZED) 784256145Sray /* Initialization already done. */ 785256145Sray return; 786256145Sray 787219888Sed cp->cn_pri = vd->vd_driver->vd_init(vd); 788219888Sed if (cp->cn_pri == CN_DEAD) { 789219888Sed vd->vd_flags |= VDF_DEAD; 790219888Sed return; 791219888Sed } 792219888Sed 793230469Snwhitehorn /* Initialize any early-boot keyboard drivers */ 794230469Snwhitehorn kbd_configure(KB_CONF_PROBE_ONLY); 795230469Snwhitehorn 796219888Sed vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 797256145Sray vd->vd_windows[VT_CONSWINDOW] = vw; 798219888Sed sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 799219888Sed 800219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 801219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 802219888Sed 803219888Sed vtbuf_init_early(&vw->vw_buf); 804219888Sed vt_winsize(vd, vw->vw_font, &wsz); 805219888Sed terminal_set_winsize(tm, &wsz); 806219888Sed 807256145Sray vtterm_splash(vd); 808219888Sed 809256145Sray vd->vd_flags |= VDF_INITIALIZED; 810256145Sray main_vd = vd; 811219888Sed} 812219888Sed 813219888Sedstatic int 814219888Sedvtterm_cngetc(struct terminal *tm) 815219888Sed{ 816219888Sed struct vt_window *vw = tm->tm_softc; 817219888Sed struct vt_device *vd = vw->vw_device; 818219888Sed keyboard_t *kbd; 819257076Sray int state; 820219888Sed u_int c; 821219888Sed 822257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 823257076Sray return (*vw->vw_kbdsq++); 824257076Sray 825257076Sray state = 0; 826219888Sed /* Make sure the splash screen is not there. */ 827219888Sed if (vd->vd_flags & VDF_SPLASH) { 828256145Sray /* Remove splash */ 829219888Sed vd->vd_flags &= ~VDF_SPLASH; 830256145Sray /* Mark screen as invalid to force update */ 831256145Sray vd->vd_flags |= VDF_INVALID; 832219888Sed vt_flush(vd); 833219888Sed } 834219888Sed 835219888Sed /* Stripped down keyboard handler. */ 836219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 837219888Sed if (kbd == NULL) 838219888Sed return (-1); 839219888Sed 840256145Sray /* Force keyboard input mode to K_XLATE */ 841256145Sray c = K_XLATE; 842256145Sray kbdd_ioctl(kbd, KDSKBMODE, (void *)&c); 843256145Sray 844219888Sed /* Switch the keyboard to polling to make it work here. */ 845219888Sed kbdd_poll(kbd, TRUE); 846219888Sed c = kbdd_read_char(kbd, 0); 847219888Sed kbdd_poll(kbd, FALSE); 848219888Sed if (c & RELKEY) 849219888Sed return (-1); 850256145Sray 851257076Sray if (vw->vw_flags & VWF_SCROLL) { 852257076Sray vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 853257076Sray vt_flush(vd); 854257076Sray return (-1); 855257076Sray } 856257076Sray 857219888Sed /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 858219888Sed if (c & SPCLKEY) { 859219888Sed switch (c) { 860257076Sray case SPCLKEY | SLK: 861219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 862219888Sed if (state & SLKED) { 863219888Sed /* Turn scrolling on. */ 864219888Sed vw->vw_flags |= VWF_SCROLL; 865256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 866219888Sed } else { 867219888Sed /* Turn scrolling off. */ 868257076Sray vt_scroll(vw, 0, VHS_END); 869219888Sed vw->vw_flags &= ~VWF_SCROLL; 870256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 871219888Sed } 872219888Sed break; 873257076Sray /* XXX: KDB can handle history. */ 874257076Sray case SPCLKEY | FKEY | F(50): /* Arrow up. */ 875257076Sray vw->vw_kbdsq = "\x1b[A"; 876219888Sed break; 877257076Sray case SPCLKEY | FKEY | F(58): /* Arrow down. */ 878257076Sray vw->vw_kbdsq = "\x1b[B"; 879219888Sed break; 880257076Sray case SPCLKEY | FKEY | F(55): /* Arrow right. */ 881257076Sray vw->vw_kbdsq = "\x1b[C"; 882219888Sed break; 883257076Sray case SPCLKEY | FKEY | F(53): /* Arrow left. */ 884257076Sray vw->vw_kbdsq = "\x1b[D"; 885219888Sed break; 886219888Sed } 887219888Sed 888219888Sed /* Force refresh to make scrollback work. */ 889219888Sed vt_flush(vd); 890219888Sed } else if (KEYFLAGS(c) == 0) { 891219888Sed return KEYCHAR(c); 892219888Sed } 893256145Sray 894257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 895257076Sray return (* 896257076Sray vw->vw_kbdsq++); 897257076Sray 898219888Sed return (-1); 899219888Sed} 900219888Sed 901219888Sedstatic void 902219888Sedvtterm_opened(struct terminal *tm, int opened) 903219888Sed{ 904219888Sed struct vt_window *vw = tm->tm_softc; 905219888Sed struct vt_device *vd = vw->vw_device; 906219888Sed 907219888Sed VT_LOCK(vd); 908219888Sed vd->vd_flags &= ~VDF_SPLASH; 909219888Sed if (opened) 910219888Sed vw->vw_flags |= VWF_OPENED; 911256145Sray else { 912219888Sed vw->vw_flags &= ~VWF_OPENED; 913256145Sray /* TODO: finish ACQ/REL */ 914256145Sray } 915219888Sed VT_UNLOCK(vd); 916219888Sed} 917219888Sed 918219888Sedstatic int 919219888Sedvt_change_font(struct vt_window *vw, struct vt_font *vf) 920219888Sed{ 921219888Sed struct vt_device *vd = vw->vw_device; 922219888Sed struct terminal *tm = vw->vw_terminal; 923219888Sed term_pos_t size; 924219888Sed struct winsize wsz; 925219888Sed 926219888Sed /* 927219888Sed * Changing fonts. 928219888Sed * 929219888Sed * Changing fonts is a little tricky. We must prevent 930219888Sed * simultaneous access to the device, so we must stop 931219888Sed * the display timer and the terminal from accessing. 932219888Sed * We need to switch fonts and grow our screen buffer. 933219888Sed * 934219888Sed * XXX: Right now the code uses terminal_mute() to 935219888Sed * prevent data from reaching the console driver while 936219888Sed * resizing the screen buffer. This isn't elegant... 937219888Sed */ 938219888Sed 939219888Sed VT_LOCK(vd); 940219888Sed if (vw->vw_flags & VWF_BUSY) { 941219888Sed /* Another process is changing the font. */ 942219888Sed VT_UNLOCK(vd); 943219888Sed return (EBUSY); 944219888Sed } 945219888Sed if (vw->vw_font == NULL) { 946219888Sed /* Our device doesn't need fonts. */ 947219888Sed VT_UNLOCK(vd); 948219888Sed return (ENOTTY); 949219888Sed } 950219888Sed vw->vw_flags |= VWF_BUSY; 951219888Sed VT_UNLOCK(vd); 952219888Sed 953219888Sed vt_termsize(vd, vf, &size); 954219888Sed vt_winsize(vd, vf, &wsz); 955257978Sray /* Save offset to font aligned area. */ 956257978Sray vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2; 957257978Sray vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2; 958219888Sed 959219888Sed /* Grow the screen buffer and terminal. */ 960219888Sed terminal_mute(tm, 1); 961256145Sray vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 962256903Sray terminal_set_winsize_blank(tm, &wsz, 0); 963219888Sed terminal_mute(tm, 0); 964219888Sed 965219888Sed /* Actually apply the font to the current window. */ 966219888Sed VT_LOCK(vd); 967219888Sed vtfont_unref(vw->vw_font); 968219888Sed vw->vw_font = vtfont_ref(vf); 969219888Sed 970219888Sed /* Force a full redraw the next timer tick. */ 971219888Sed if (vd->vd_curwindow == vw) 972219888Sed vd->vd_flags |= VDF_INVALID; 973219888Sed vw->vw_flags &= ~VWF_BUSY; 974219888Sed VT_UNLOCK(vd); 975219888Sed return (0); 976219888Sed} 977219888Sed 978219888Sedstatic int 979256145Srayvt_proc_alive(struct vt_window *vw) 980256145Sray{ 981256145Sray struct proc *p; 982256145Sray 983256145Sray if (vw->vw_smode.mode != VT_PROCESS) 984256145Sray return FALSE; 985256145Sray 986256145Sray if (vw->vw_proc) { 987256145Sray if ((p = pfind(vw->vw_pid)) != NULL) 988256145Sray PROC_UNLOCK(p); 989256145Sray if (vw->vw_proc == p) 990256145Sray return TRUE; 991256145Sray vw->vw_proc = NULL; 992256145Sray vw->vw_smode.mode = VT_AUTO; 993256145Sray DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 994256145Sray vw->vw_pid = 0; 995256145Sray } 996256145Sray return FALSE; 997256145Sray} 998256145Sray 999256145Sraystatic int 1000256145Sraysignal_vt_rel(struct vt_window *vw) 1001256145Sray{ 1002257815Sray 1003256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1004256145Sray return FALSE; 1005256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1006256145Sray vw->vw_proc = NULL; 1007256145Sray vw->vw_pid = 0; 1008256145Sray return TRUE; 1009256145Sray } 1010256145Sray vw->vw_flags |= VWF_SWWAIT_REL; 1011256145Sray PROC_LOCK(vw->vw_proc); 1012256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 1013256145Sray PROC_UNLOCK(vw->vw_proc); 1014256145Sray DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 1015256145Sray return TRUE; 1016256145Sray} 1017256145Sray 1018256145Sraystatic int 1019256145Sraysignal_vt_acq(struct vt_window *vw) 1020256145Sray{ 1021257815Sray 1022256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1023256145Sray return FALSE; 1024256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1025256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1026256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1027256145Sray vw->vw_proc = NULL; 1028256145Sray vw->vw_pid = 0; 1029256145Sray return TRUE; 1030256145Sray } 1031256145Sray vw->vw_flags |= VWF_SWWAIT_ACQ; 1032256145Sray PROC_LOCK(vw->vw_proc); 1033256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1034256145Sray PROC_UNLOCK(vw->vw_proc); 1035256145Sray DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1036256145Sray return TRUE; 1037256145Sray} 1038256145Sray 1039256145Sraystatic int 1040256145Srayfinish_vt_rel(struct vt_window *vw, int release, int *s) 1041256145Sray{ 1042257815Sray 1043256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1044256145Sray vw->vw_flags &= ~VWF_SWWAIT_REL; 1045256145Sray if (release) { 1046256145Sray callout_drain(&vw->vw_proc_dead_timer); 1047256145Sray vt_late_window_switch(vw->vw_switch_to); 1048256145Sray } 1049256145Sray return 0; 1050256145Sray } 1051256145Sray return EINVAL; 1052256145Sray} 1053256145Sray 1054256145Sraystatic int 1055256145Srayfinish_vt_acq(struct vt_window *vw) 1056256145Sray{ 1057257815Sray 1058256145Sray if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1059256145Sray vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1060256145Sray return 0; 1061256145Sray } 1062256145Sray return EINVAL; 1063256145Sray} 1064256145Sray 1065257977Srayvoid 1066257977Srayvt_mouse_event(int type, int x, int y, int event, int cnt) 1067257977Sray{ 1068257977Sray struct vt_device *vd; 1069257977Sray struct vt_window *vw; 1070257977Sray struct vt_font *vf; 1071257977Sray term_pos_t size; 1072257977Sray int mark; 1073257977Sray 1074257977Sray vd = main_vd; 1075257977Sray vw = vd->vd_curwindow; 1076257977Sray vf = vw->vw_font; 1077257977Sray 1078257977Sray if (vf == NULL) /* Text mode. */ 1079257977Sray return; 1080257977Sray 1081257977Sray /* 1082257977Sray * TODO: add flag about pointer position changed, to not redraw chars 1083257977Sray * under mouse pointer when nothing changed. 1084257977Sray */ 1085257977Sray 1086257977Sray switch (type) { 1087257977Sray case MOUSE_ACTION: 1088257977Sray case MOUSE_MOTION_EVENT: 1089257977Sray /* Movement */ 1090257977Sray x += vd->vd_mx; 1091257977Sray y += vd->vd_my; 1092257977Sray 1093257977Sray vt_termsize(vd, vf, &size); 1094257977Sray 1095257977Sray /* Apply limits. */ 1096257977Sray x = MAX(x, 0); 1097257977Sray y = MAX(y, 0); 1098257977Sray x = MIN(x, (size.tp_col * vf->vf_width) - 1); 1099257977Sray y = MIN(y, (size.tp_row * vf->vf_height) - 1); 1100257977Sray 1101257977Sray vd->vd_mx = x; 1102257977Sray vd->vd_my = y; 1103257977Sray if (vd->vd_mstate & MOUSE_BUTTON1DOWN) 1104257977Sray vtbuf_set_mark(&vw->vw_buf, VTB_MARK_END, 1105257977Sray vd->vd_mx / vf->vf_width, 1106257977Sray vd->vd_my / vf->vf_height); 1107257977Sray return; /* Done */ 1108257977Sray case MOUSE_BUTTON_EVENT: 1109257977Sray /* Buttons */ 1110257977Sray break; 1111257977Sray default: 1112257977Sray return; /* Done */ 1113257977Sray } 1114257977Sray 1115257977Sray switch (event) { 1116257977Sray case MOUSE_BUTTON1DOWN: 1117257977Sray switch (cnt % 4) { 1118257977Sray case 0: /* up */ 1119257977Sray mark = VTB_MARK_END; 1120257977Sray break; 1121257977Sray case 1: /* single click: start cut operation */ 1122257977Sray mark = VTB_MARK_START; 1123257977Sray break; 1124257977Sray case 2: /* double click: cut a word */ 1125257977Sray mark = VTB_MARK_WORD; 1126257977Sray break; 1127257977Sray case 3: /* triple click: cut a line */ 1128257977Sray mark = VTB_MARK_ROW; 1129257977Sray break; 1130257977Sray } 1131257977Sray break; 1132257977Sray case VT_MOUSE_PASTEBUTTON: 1133257977Sray switch (event) { 1134257977Sray case 0: /* up */ 1135257977Sray break; 1136257977Sray default: 1137257977Sray //sc_mouse_paste(cur_scp); 1138257977Sray break; 1139257977Sray } 1140257977Sray return; /* Done */ 1141257977Sray case VT_MOUSE_EXTENDBUTTON: 1142257977Sray switch (event) { 1143257977Sray case 0: /* up */ 1144257977Sray if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 1145257977Sray mark = VTB_MARK_END; 1146257977Sray else 1147257977Sray mark = 0; 1148257977Sray break; 1149257977Sray default: 1150257977Sray mark = VTB_MARK_EXTEND; 1151257977Sray break; 1152257977Sray } 1153257977Sray break; 1154257977Sray default: 1155257977Sray return; /* Done */ 1156257977Sray } 1157257977Sray 1158257977Sray /* Save buttons state. */ 1159257977Sray if (cnt > 0) 1160257977Sray vd->vd_mstate |= event; 1161257977Sray else 1162257977Sray vd->vd_mstate &= ~event; 1163257977Sray 1164257977Sray vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 1165257977Sray vd->vd_my / vf->vf_height); 1166257977Sray} 1167257977Sray 1168256145Sraystatic int 1169219888Sedvtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1170219888Sed struct thread *td) 1171219888Sed{ 1172219888Sed struct vt_window *vw = tm->tm_softc; 1173219888Sed struct vt_device *vd = vw->vw_device; 1174256145Sray int error, s; 1175219888Sed 1176219888Sed switch (cmd) { 1177219888Sed case GIO_KEYMAP: 1178219888Sed case PIO_KEYMAP: 1179219888Sed case GIO_DEADKEYMAP: 1180219888Sed case PIO_DEADKEYMAP: 1181219888Sed case GETFKEY: 1182219888Sed case SETFKEY: 1183219888Sed case KDGKBINFO: { 1184219888Sed keyboard_t *kbd; 1185256145Sray error = 0; 1186219888Sed 1187219888Sed mtx_lock(&Giant); 1188219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1189219888Sed if (kbd != NULL) 1190219888Sed error = kbdd_ioctl(kbd, cmd, data); 1191219888Sed mtx_unlock(&Giant); 1192219888Sed if (error == ENOIOCTL) 1193219888Sed return (ENODEV); 1194219888Sed return (error); 1195219888Sed } 1196256145Sray case KDGKBMODE: { 1197256145Sray int mode = -1; 1198256145Sray keyboard_t *kbd; 1199256145Sray 1200256145Sray mtx_lock(&Giant); 1201256145Sray kbd = kbd_get_keyboard(vd->vd_keyboard); 1202256145Sray if (kbd != NULL) { 1203256145Sray kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1204256145Sray } 1205256145Sray mtx_unlock(&Giant); 1206256145Sray DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1207256145Sray *(int *)data = mode; 1208256145Sray return (0); 1209256145Sray } 1210219888Sed case KDSKBMODE: { 1211219888Sed int mode; 1212219888Sed 1213219888Sed mode = *(int *)data; 1214219888Sed switch (mode) { 1215219888Sed case K_XLATE: 1216219888Sed case K_RAW: 1217219888Sed case K_CODE: 1218219888Sed vw->vw_kbdmode = mode; 1219219888Sed if (vw == vd->vd_curwindow) { 1220219888Sed keyboard_t *kbd; 1221256145Sray error = 0; 1222219888Sed 1223257983Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, 1224257983Sray vd->vd_keyboard); 1225219888Sed mtx_lock(&Giant); 1226219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1227256145Sray if (kbd != NULL) { 1228256145Sray DPRINTF(20, "kbdd_ioctl(KDSKBMODE, %d)\n", mode); 1229256145Sray error = kbdd_ioctl(kbd, KDSKBMODE, 1230219888Sed (void *)&mode); 1231256145Sray } 1232219888Sed mtx_unlock(&Giant); 1233256145Sray if (error) 1234257983Sray DPRINTF(20, "kbdd_ioctl(KDSKBMODE) " 1235257983Sray "return %d\n", error); 1236219888Sed } 1237219888Sed return (0); 1238219888Sed default: 1239219888Sed return (EINVAL); 1240219888Sed } 1241219888Sed } 1242219888Sed case CONS_BLANKTIME: 1243219888Sed /* XXX */ 1244219888Sed return (0); 1245219888Sed case CONS_GET: 1246219888Sed /* XXX */ 1247219888Sed *(int *)data = M_CG640x480; 1248219888Sed return (0); 1249219888Sed case CONS_GETINFO: { 1250219888Sed vid_info_t *vi = (vid_info_t *)data; 1251219888Sed 1252219888Sed vi->m_num = vd->vd_curwindow->vw_number + 1; 1253219888Sed /* XXX: other fields! */ 1254219888Sed return (0); 1255219888Sed } 1256219888Sed case CONS_GETVERS: 1257219888Sed *(int *)data = 0x200; 1258219888Sed return 0; 1259219888Sed case CONS_MODEINFO: 1260219888Sed /* XXX */ 1261219888Sed return (0); 1262219888Sed case CONS_MOUSECTL: { 1263219888Sed mouse_info_t *mouse = (mouse_info_t*)data; 1264219888Sed 1265219888Sed /* 1266219888Sed * This has no effect on vt(4). We don't draw any mouse 1267219888Sed * cursor. Just ignore MOUSE_HIDE and MOUSE_SHOW to 1268219888Sed * prevent excessive errors. All the other commands 1269219888Sed * should not be applied to individual TTYs, but only to 1270219888Sed * consolectl. 1271219888Sed */ 1272219888Sed switch (mouse->operation) { 1273219888Sed case MOUSE_HIDE: 1274257982Sray vd->vd_flags &= ~VDF_MOUSECURSOR; 1275257982Sray return (0); 1276219888Sed case MOUSE_SHOW: 1277257982Sray vd->vd_mx = vd->vd_width / 2; 1278257982Sray vd->vd_my = vd->vd_height / 2; 1279257982Sray vd->vd_flags |= VDF_MOUSECURSOR; 1280219888Sed return (0); 1281219888Sed default: 1282219888Sed return (EINVAL); 1283219888Sed } 1284219888Sed } 1285219888Sed case PIO_VFONT: { 1286219888Sed struct vt_font *vf; 1287219888Sed 1288219888Sed error = vtfont_load((void *)data, &vf); 1289219888Sed if (error != 0) 1290219888Sed return (error); 1291219888Sed 1292219888Sed error = vt_change_font(vw, vf); 1293219888Sed vtfont_unref(vf); 1294219888Sed return (error); 1295219888Sed } 1296219888Sed case GIO_SCRNMAP: { 1297219888Sed scrmap_t *sm = (scrmap_t *)data; 1298219888Sed int i; 1299219888Sed 1300219888Sed /* We don't have screen maps, so return a handcrafted one. */ 1301219888Sed for (i = 0; i < 256; i++) 1302219888Sed sm->scrmap[i] = i; 1303219888Sed return (0); 1304219888Sed } 1305219888Sed case KDGETLED: 1306219888Sed /* XXX */ 1307219888Sed return (0); 1308219888Sed case KDSETLED: 1309219888Sed /* XXX */ 1310219888Sed return (0); 1311219888Sed case KDSETMODE: 1312219888Sed /* XXX */ 1313219888Sed return (0); 1314219888Sed case KDSETRAD: 1315219888Sed /* XXX */ 1316219888Sed return (0); 1317256145Sray case VT_ACTIVATE: { 1318256145Sray int win; 1319256145Sray win = *(int *)data - 1; 1320256145Sray DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, VT_UNIT(vw), win); 1321256145Sray if ((win > VT_MAXWINDOWS) || (win < 0)) 1322256145Sray return (EINVAL); 1323256145Sray return (vt_proc_window_switch(vd->vd_windows[win])); 1324256145Sray } 1325219888Sed case VT_GETACTIVE: 1326219888Sed *(int *)data = vd->vd_curwindow->vw_number + 1; 1327219888Sed return (0); 1328219888Sed case VT_GETINDEX: 1329219888Sed *(int *)data = vw->vw_number + 1; 1330219888Sed return (0); 1331256145Sray case VT_LOCKSWITCH: 1332256145Sray /* TODO: Check current state, switching can be in progress. */ 1333256145Sray if ((*(int *)data) & 0x01) 1334256145Sray vw->vw_flags |= VWF_VTYLOCK; 1335256145Sray else 1336256145Sray vw->vw_flags &= ~VWF_VTYLOCK; 1337219888Sed case VT_OPENQRY: { 1338219888Sed unsigned int i; 1339219888Sed 1340219888Sed VT_LOCK(vd); 1341219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1342219888Sed vw = vd->vd_windows[i]; 1343219888Sed if (vw == NULL) 1344219888Sed continue; 1345219888Sed if (!(vw->vw_flags & VWF_OPENED)) { 1346219888Sed *(int *)data = vw->vw_number + 1; 1347219888Sed VT_UNLOCK(vd); 1348219888Sed return (0); 1349219888Sed } 1350219888Sed } 1351219888Sed VT_UNLOCK(vd); 1352219888Sed return (EINVAL); 1353219888Sed } 1354219888Sed case VT_WAITACTIVE: { 1355219888Sed unsigned int i; 1356256145Sray error = 0; 1357219888Sed 1358219888Sed i = *(unsigned int *)data; 1359219888Sed if (i > VT_MAXWINDOWS) 1360219888Sed return (EINVAL); 1361219888Sed if (i != 0) 1362219888Sed vw = vd->vd_windows[i - 1]; 1363219888Sed 1364219888Sed VT_LOCK(vd); 1365219888Sed while (vd->vd_curwindow != vw && error == 0) 1366219888Sed error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 1367219888Sed VT_UNLOCK(vd); 1368219888Sed return (error); 1369219888Sed } 1370256145Sray case VT_SETMODE: /* set screen switcher mode */ 1371256145Sray { 1372256145Sray struct vt_mode *mode; 1373256145Sray struct proc *p1; 1374256145Sray 1375256145Sray mode = (struct vt_mode *)data; 1376256145Sray DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 1377256145Sray if (vw->vw_smode.mode == VT_PROCESS) { 1378256145Sray p1 = pfind(vw->vw_pid); 1379256145Sray if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 1380256145Sray if (p1) 1381256145Sray PROC_UNLOCK(p1); 1382256145Sray DPRINTF(5, "error EPERM\n"); 1383256145Sray return (EPERM); 1384256145Sray } 1385256145Sray if (p1) 1386256145Sray PROC_UNLOCK(p1); 1387256145Sray } 1388256145Sray if (mode->mode == VT_AUTO) { 1389256145Sray vw->vw_smode.mode = VT_AUTO; 1390256145Sray vw->vw_proc = NULL; 1391256145Sray vw->vw_pid = 0; 1392256145Sray DPRINTF(5, "VT_AUTO, "); 1393256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1394256145Sray cnavailable(vw->vw_terminal->consdev, TRUE); 1395256145Sray /* were we in the middle of the vty switching process? */ 1396256145Sray if (finish_vt_rel(vw, TRUE, &s) == 0) 1397256145Sray DPRINTF(5, "reset WAIT_REL, "); 1398256145Sray if (finish_vt_acq(vw) == 0) 1399256145Sray DPRINTF(5, "reset WAIT_ACQ, "); 1400256145Sray return (0); 1401256145Sray } else if (mode->mode == VT_PROCESS) { 1402256145Sray if (!ISSIGVALID(mode->relsig) || 1403256145Sray !ISSIGVALID(mode->acqsig) || 1404256145Sray !ISSIGVALID(mode->frsig)) { 1405256145Sray DPRINTF(5, "error EINVAL\n"); 1406256145Sray return (EINVAL); 1407256145Sray } 1408256145Sray DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 1409256145Sray bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 1410256145Sray vw->vw_proc = td->td_proc; 1411256145Sray vw->vw_pid = vw->vw_proc->p_pid; 1412256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1413256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1414256145Sray } else { 1415256145Sray DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 1416256145Sray mode->mode); 1417256145Sray return (EINVAL); 1418256145Sray } 1419256145Sray DPRINTF(5, "\n"); 1420256145Sray return 0; 1421219888Sed } 1422219888Sed 1423256145Sray case VT_GETMODE: /* get screen switcher mode */ 1424256145Sray bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 1425256145Sray return 0; 1426256145Sray 1427256145Sray case VT_RELDISP: /* screen switcher ioctl */ 1428256145Sray /* 1429256145Sray * This must be the current vty which is in the VT_PROCESS 1430256145Sray * switching mode... 1431256145Sray */ 1432256145Sray if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 1433256145Sray VT_PROCESS)) { 1434256145Sray return EINVAL; 1435256145Sray } 1436256145Sray /* ...and this process is controlling it. */ 1437256145Sray if (vw->vw_proc != td->td_proc) { 1438256145Sray return EPERM; 1439256145Sray } 1440256145Sray error = EINVAL; 1441256145Sray switch(*(int *)data) { 1442256145Sray case VT_FALSE: /* user refuses to release screen, abort */ 1443256145Sray if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 1444256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", SC_DRIVER_NAME, 1445256145Sray VT_UNIT(vw)); 1446256145Sray break; 1447256145Sray case VT_TRUE: /* user has released screen, go on */ 1448256145Sray /* finish_vt_rel(..., TRUE, ...) should not be locked */ 1449256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1450256145Sray if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 1451256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 1452256145Sray SC_DRIVER_NAME, VT_UNIT(vw)); 1453256145Sray } else { 1454256145Sray error = EINVAL; 1455256145Sray } 1456256145Sray return (error); 1457256145Sray case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1458256145Sray if ((error = finish_vt_acq(vw)) == 0) 1459256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", SC_DRIVER_NAME, 1460256145Sray VT_UNIT(vw)); 1461256145Sray break; 1462256145Sray default: 1463256145Sray break; 1464256145Sray } 1465256145Sray return error; 1466256145Sray } 1467256145Sray 1468219888Sed return (ENOIOCTL); 1469219888Sed} 1470219888Sed 1471219888Sedstatic struct vt_window * 1472219888Sedvt_allocate_window(struct vt_device *vd, unsigned int window) 1473219888Sed{ 1474219888Sed struct vt_window *vw; 1475219888Sed struct terminal *tm; 1476219888Sed term_pos_t size; 1477219888Sed struct winsize wsz; 1478219888Sed 1479219888Sed vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 1480219888Sed vw->vw_device = vd; 1481219888Sed vw->vw_number = window; 1482219888Sed vw->vw_kbdmode = K_XLATE; 1483219888Sed 1484219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 1485219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 1486256145Sray 1487219888Sed vt_termsize(vd, vw->vw_font, &size); 1488219888Sed vt_winsize(vd, vw->vw_font, &wsz); 1489219888Sed vtbuf_init(&vw->vw_buf, &size); 1490219888Sed 1491219888Sed tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 1492219888Sed terminal_set_winsize(tm, &wsz); 1493219888Sed vd->vd_windows[window] = vw; 1494256145Sray callout_init(&vw->vw_proc_dead_timer, 0); 1495219888Sed 1496219888Sed return (vw); 1497219888Sed} 1498219888Sed 1499219888Sedvoid 1500219888Sedvt_upgrade(struct vt_device *vd) 1501219888Sed{ 1502219888Sed struct vt_window *vw; 1503219888Sed unsigned int i; 1504219888Sed 1505256145Sray /* Device didn't pass vd_init() or already upgraded. */ 1506256145Sray if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD)) 1507219888Sed return; 1508256145Sray vd->vd_flags |= VDF_ASYNC; 1509219888Sed 1510219888Sed mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); 1511219888Sed cv_init(&vd->vd_winswitch, "vtwswt"); 1512219888Sed 1513256145Sray /* Init 25 Hz timer. */ 1514219888Sed callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 1515219888Sed 1516219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1517219888Sed vw = vd->vd_windows[i]; 1518219888Sed if (vw == NULL) { 1519219888Sed /* New window. */ 1520219888Sed vw = vt_allocate_window(vd, i); 1521256145Sray } 1522256145Sray if (i == VT_CONSWINDOW) { 1523219888Sed /* Console window. */ 1524219888Sed EVENTHANDLER_REGISTER(shutdown_pre_sync, 1525219888Sed vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 1526219888Sed } 1527219888Sed terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 1528219888Sed } 1529256145Sray if (vd->vd_curwindow == NULL) 1530256145Sray vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 1531219888Sed 1532219888Sed /* Attach keyboard. */ 1533219888Sed vt_allocate_keyboard(vd); 1534256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 1535256145Sray 1536256145Sray /* Start timer when everything ready. */ 1537256145Sray callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 1538219888Sed} 1539219888Sed 1540256145Sraystatic void 1541256145Srayvt_resize(struct vt_device *vd) 1542256145Sray{ 1543256145Sray struct vt_window *vw; 1544256145Sray int i; 1545256145Sray 1546256145Sray for (i = 0; i < VT_MAXWINDOWS; i++) { 1547256145Sray vw = vd->vd_windows[i]; 1548256145Sray /* Resize terminal windows */ 1549256145Sray vt_change_font(vw, vw->vw_font); 1550256145Sray } 1551256145Sray} 1552256145Sray 1553219888Sedvoid 1554219888Sedvt_allocate(struct vt_driver *drv, void *softc) 1555219888Sed{ 1556219888Sed struct vt_device *vd; 1557256903Sray struct winsize wsz; 1558219888Sed 1559256145Sray if (main_vd == NULL) { 1560256145Sray main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); 1561256903Sray printf("%s: VT initialize with new VT driver.\n", __func__); 1562256145Sray } else { 1563256145Sray /* 1564256145Sray * Check if have rights to replace current driver. For example: 1565256145Sray * it is bad idea to replace KMS driver with generic VGA one. 1566256145Sray */ 1567256903Sray if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 1568256903Sray printf("%s: Driver priority %d too low. Current %d\n ", 1569256903Sray __func__, drv->vd_priority, 1570256903Sray main_vd->vd_driver->vd_priority); 1571256145Sray return; 1572256903Sray } 1573256903Sray printf("%s: Replace existing VT driver.\n", __func__); 1574256145Sray } 1575256145Sray vd = main_vd; 1576256145Sray 1577256527Sray /* Stop vt_flush periodic task. */ 1578256145Sray if (vd->vd_curwindow != NULL) 1579256145Sray callout_drain(&vd->vd_timer); 1580256145Sray 1581219888Sed vd->vd_driver = drv; 1582219888Sed vd->vd_softc = softc; 1583219888Sed vd->vd_driver->vd_init(vd); 1584256145Sray 1585219888Sed vt_upgrade(vd); 1586256145Sray 1587256145Sray /* Refill settings with new sizes. */ 1588256145Sray vt_resize(vd); 1589256145Sray 1590256145Sray if (vd->vd_flags & VDF_SPLASH) 1591256145Sray vtterm_splash(vd); 1592256145Sray 1593256145Sray if (vd->vd_curwindow != NULL) 1594256145Sray callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 1595256145Sray 1596256145Sray termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 1597256903Sray 1598256903Sray /* Update console window sizes to actual. */ 1599256903Sray vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz); 1600256903Sray terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz); 1601219888Sed} 1602257815Sray 1603257815Srayvoid 1604257815Srayvt_suspend() 1605257815Sray{ 1606257815Sray 1607258023Sray if (vt_suspendswitch == 0) 1608258023Sray return; 1609257815Sray /* Save current window. */ 1610257815Sray main_vd->vd_savedwindow = main_vd->vd_curwindow; 1611257815Sray /* Ask holding process to free window and switch to console window */ 1612257815Sray vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]); 1613257815Sray} 1614257815Sray 1615257815Srayvoid 1616257815Srayvt_resume() 1617257815Sray{ 1618257815Sray 1619258023Sray if (vt_suspendswitch == 0) 1620258023Sray return; 1621257815Sray /* Switch back to saved window */ 1622257815Sray if (main_vd->vd_savedwindow != NULL) 1623257815Sray vt_proc_window_switch(main_vd->vd_savedwindow); 1624257815Sray main_vd->vd_savedwindow = NULL; 1625257815Sray} 1626