vt_core.c revision 258781
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 258781 2013-11-30 22:46:43Z nwhitehorn $"); 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); 358258408Sray vw->vw_flags &= ~VWF_SCROLL; 359257076Sray break; 360257076Sray } 361257076Sray case FKEY | F(49): /* Home key. */ 362258506Sray vt_scroll(vw, 0, VHS_SET); 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. */ 372258506Sray vt_scroll(vw, 0, VHS_END); 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 393258165Sray#if VT_ALT_TO_ESC_HACK 394258165Sray if (c & RELKEY) { 395258165Sray switch (c & ~RELKEY) { 396258165Sray case (SPCLKEY | RALT): 397258165Sray case (SPCLKEY | LALT): 398258165Sray vd->vd_kbstate &= ~ALKED; 399258165Sray } 400258165Sray /* Other keys ignored for RELKEY event. */ 401258165Sray return (0); 402258165Sray } else { 403258165Sray switch (c & ~RELKEY) { 404258165Sray case (SPCLKEY | RALT): 405258165Sray case (SPCLKEY | LALT): 406258165Sray vd->vd_kbstate |= ALKED; 407258165Sray } 408258165Sray } 409258165Sray#else 410219888Sed if (c & RELKEY) 411258165Sray /* Other keys ignored for RELKEY event. */ 412219888Sed return (0); 413258165Sray#endif 414219888Sed 415257076Sray if (vt_machine_kbdevent(c)) 416257076Sray return (0); 417257076Sray 418257076Sray if (vw->vw_flags & VWF_SCROLL) { 419257076Sray vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 420257076Sray /* Scroll mode keys handled, nothing to do more. */ 421257076Sray return (0); 422257076Sray } 423257076Sray 424219888Sed if (c & SPCLKEY) { 425219888Sed c &= ~SPCLKEY; 426219888Sed 427219888Sed if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 428219888Sed vw = vd->vd_windows[c - F_SCR]; 429219888Sed if (vw != NULL) 430256145Sray vt_proc_window_switch(vw); 431219888Sed return (0); 432219888Sed } 433219888Sed 434219888Sed switch (c) { 435219888Sed case SLK: { 436219888Sed 437219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 438219888Sed VT_LOCK(vd); 439219888Sed if (state & SLKED) { 440219888Sed /* Turn scrolling on. */ 441258408Sray vw->vw_flags |= VWF_SCROLL; 442256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 443219888Sed } else { 444219888Sed /* Turn scrolling off. */ 445258408Sray vw->vw_flags &= ~VWF_SCROLL; 446256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 447257076Sray vt_scroll(vw, 0, VHS_END); 448219888Sed } 449219888Sed VT_UNLOCK(vd); 450219888Sed break; 451219888Sed } 452219888Sed case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 453219888Sed case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 454219888Sed case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 455219888Sed case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 456219888Sed /* F1 through F12 keys. */ 457219888Sed terminal_input_special(vw->vw_terminal, 458219888Sed TKEY_F1 + c - (FKEY | F(1))); 459219888Sed break; 460219888Sed case FKEY | F(49): /* Home key. */ 461219888Sed terminal_input_special(vw->vw_terminal, TKEY_HOME); 462219888Sed break; 463219888Sed case FKEY | F(50): /* Arrow up. */ 464219888Sed terminal_input_special(vw->vw_terminal, TKEY_UP); 465219888Sed break; 466219888Sed case FKEY | F(51): /* Page up. */ 467219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 468219888Sed break; 469219888Sed case FKEY | F(53): /* Arrow left. */ 470219888Sed terminal_input_special(vw->vw_terminal, TKEY_LEFT); 471219888Sed break; 472219888Sed case FKEY | F(55): /* Arrow right. */ 473219888Sed terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 474219888Sed break; 475219888Sed case FKEY | F(57): /* End key. */ 476219888Sed terminal_input_special(vw->vw_terminal, TKEY_END); 477219888Sed break; 478219888Sed case FKEY | F(58): /* Arrow down. */ 479219888Sed terminal_input_special(vw->vw_terminal, TKEY_DOWN); 480219888Sed break; 481219888Sed case FKEY | F(59): /* Page down. */ 482219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 483219888Sed break; 484219888Sed case FKEY | F(60): /* Insert key. */ 485219888Sed terminal_input_special(vw->vw_terminal, TKEY_INSERT); 486219888Sed break; 487219888Sed case FKEY | F(61): /* Delete key. */ 488219888Sed terminal_input_special(vw->vw_terminal, TKEY_DELETE); 489219888Sed break; 490219888Sed } 491219888Sed } else if (KEYFLAGS(c) == 0) { 492219888Sed /* Don't do UTF-8 conversion when doing raw mode. */ 493258165Sray if (vw->vw_kbdmode == K_XLATE) { 494258165Sray#if VT_ALT_TO_ESC_HACK 495258165Sray if (vd->vd_kbstate & ALKED) { 496258165Sray /* 497258165Sray * Prepend ESC sequence if one of ALT keys down. 498258165Sray */ 499258165Sray terminal_input_char(vw->vw_terminal, 0x1b); 500258165Sray } 501258165Sray#endif 502258165Sray 503256145Sray terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 504258165Sray } else 505219888Sed terminal_input_raw(vw->vw_terminal, c); 506219888Sed } 507219888Sed return (0); 508219888Sed} 509219888Sed 510219888Sedstatic int 511257294Snwhitehornvt_kbdevent(keyboard_t *kbd, int event, void *arg) 512257294Snwhitehorn{ 513257294Snwhitehorn struct vt_device *vd = arg; 514257294Snwhitehorn int c; 515257294Snwhitehorn 516257294Snwhitehorn switch (event) { 517257294Snwhitehorn case KBDIO_KEYINPUT: 518257294Snwhitehorn break; 519257294Snwhitehorn case KBDIO_UNLOADING: 520257294Snwhitehorn mtx_lock(&Giant); 521257294Snwhitehorn vd->vd_keyboard = -1; 522257294Snwhitehorn kbd_release(kbd, (void *)&vd->vd_keyboard); 523257294Snwhitehorn mtx_unlock(&Giant); 524257294Snwhitehorn return (0); 525257294Snwhitehorn default: 526257294Snwhitehorn return (EINVAL); 527257294Snwhitehorn } 528257294Snwhitehorn 529257294Snwhitehorn while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 530257294Snwhitehorn vt_processkey(kbd, vd, c); 531257294Snwhitehorn 532257294Snwhitehorn return (0); 533257294Snwhitehorn} 534257294Snwhitehorn 535257294Snwhitehornstatic int 536219888Sedvt_allocate_keyboard(struct vt_device *vd) 537219888Sed{ 538219888Sed int idx0, idx; 539219888Sed keyboard_t *k0, *k; 540219888Sed keyboard_info_t ki; 541219888Sed 542219888Sed idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard, 543219888Sed vt_kbdevent, vd); 544256145Sray /* XXX: kb_token lost */ 545256145Sray vd->vd_keyboard = idx0; 546219888Sed if (idx0 != -1) { 547256145Sray DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 548219888Sed k0 = kbd_get_keyboard(idx0); 549219888Sed 550219888Sed for (idx = kbd_find_keyboard2("*", -1, 0); 551219888Sed idx != -1; 552219888Sed idx = kbd_find_keyboard2("*", -1, idx + 1)) { 553219888Sed k = kbd_get_keyboard(idx); 554219888Sed 555219888Sed if (idx == idx0 || KBD_IS_BUSY(k)) 556219888Sed continue; 557219888Sed 558219888Sed bzero(&ki, sizeof(ki)); 559219888Sed strcpy(ki.kb_name, k->kb_name); 560219888Sed ki.kb_unit = k->kb_unit; 561219888Sed 562219888Sed kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 563219888Sed } 564256145Sray } else { 565256145Sray DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 566219888Sed idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard, 567219888Sed vt_kbdevent, vd); 568256145Sray } 569256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 570219888Sed 571219888Sed return (idx0); 572219888Sed} 573219888Sed 574219888Sedstatic void 575219888Sedvtterm_bell(struct terminal *tm) 576219888Sed{ 577219888Sed 578219888Sed sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION); 579219888Sed} 580219888Sed 581219888Sedstatic void 582219888Sedvtterm_cursor(struct terminal *tm, const term_pos_t *p) 583219888Sed{ 584219888Sed struct vt_window *vw = tm->tm_softc; 585219888Sed 586219888Sed vtbuf_cursor_position(&vw->vw_buf, p); 587219888Sed} 588219888Sed 589219888Sedstatic void 590219888Sedvtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 591219888Sed{ 592219888Sed struct vt_window *vw = tm->tm_softc; 593219888Sed 594219888Sed vtbuf_putchar(&vw->vw_buf, p, c); 595219888Sed} 596219888Sed 597219888Sedstatic void 598219888Sedvtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 599219888Sed{ 600219888Sed struct vt_window *vw = tm->tm_softc; 601219888Sed 602256145Sray vtbuf_fill_locked(&vw->vw_buf, r, c); 603219888Sed} 604219888Sed 605219888Sedstatic void 606219888Sedvtterm_copy(struct terminal *tm, const term_rect_t *r, 607219888Sed const term_pos_t *p) 608219888Sed{ 609219888Sed struct vt_window *vw = tm->tm_softc; 610219888Sed 611219888Sed vtbuf_copy(&vw->vw_buf, r, p); 612219888Sed} 613219888Sed 614219888Sedstatic void 615219888Sedvtterm_param(struct terminal *tm, int cmd, unsigned int arg) 616219888Sed{ 617219888Sed struct vt_window *vw = tm->tm_softc; 618219888Sed 619219888Sed switch (cmd) { 620219888Sed case TP_SHOWCURSOR: 621219888Sed vtbuf_cursor_visibility(&vw->vw_buf, arg); 622219888Sed break; 623219888Sed } 624219888Sed} 625219888Sed 626219888Sedstatic inline void 627219888Sedvt_determine_colors(term_char_t c, int cursor, 628219888Sed term_color_t *fg, term_color_t *bg) 629219888Sed{ 630219888Sed 631219888Sed *fg = TCHAR_FGCOLOR(c); 632219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) 633219888Sed *fg = TCOLOR_LIGHT(*fg); 634219888Sed *bg = TCHAR_BGCOLOR(c); 635219888Sed 636219888Sed if (TCHAR_FORMAT(c) & TF_REVERSE) { 637219888Sed term_color_t tmp; 638219888Sed 639219888Sed tmp = *fg; 640219888Sed *fg = *bg; 641219888Sed *bg = tmp; 642219888Sed } 643219888Sed 644219888Sed if (cursor) { 645219888Sed *fg = *bg; 646219888Sed *bg = TC_WHITE; 647219888Sed } 648219888Sed} 649219888Sed 650219888Sedstatic void 651219888Sedvt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c, 652219888Sed int iscursor, unsigned int row, unsigned int col) 653219888Sed{ 654219888Sed term_color_t fg, bg; 655219888Sed 656219888Sed vt_determine_colors(c, iscursor, &fg, &bg); 657219888Sed 658219888Sed if (vf != NULL) { 659219888Sed const uint8_t *src; 660219888Sed vt_axis_t top, left; 661219888Sed 662219888Sed src = vtfont_lookup(vf, c); 663219888Sed 664219888Sed /* 665219888Sed * Align the terminal to the centre of the screen. 666219888Sed * Fonts may not always be able to fill the entire 667219888Sed * screen. 668219888Sed */ 669257979Sray top = row * vf->vf_height + vd->vd_offset.tp_row; 670257979Sray left = col * vf->vf_width + vd->vd_offset.tp_col; 671219888Sed 672257988Sray vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left, 673219888Sed vf->vf_width, vf->vf_height, fg, bg); 674219888Sed } else { 675219888Sed vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c), 676219888Sed row, col, fg, bg); 677219888Sed } 678219888Sed} 679219888Sed 680219888Sedstatic void 681219888Sedvt_flush(struct vt_device *vd) 682219888Sed{ 683219888Sed struct vt_window *vw = vd->vd_curwindow; 684219888Sed struct vt_font *vf = vw->vw_font; 685219888Sed struct vt_bufmask tmask; 686257981Sray struct mouse_cursor *m; 687256145Sray unsigned int row, col; 688257981Sray term_rect_t tarea; 689257981Sray term_pos_t size; 690256145Sray term_char_t *r; 691257988Sray int bpl, h, w; 692219888Sed 693219888Sed if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY) 694219888Sed return; 695219888Sed 696219888Sed vtbuf_undirty(&vw->vw_buf, &tarea, &tmask); 697219888Sed vt_termsize(vd, vf, &size); 698219888Sed 699219888Sed /* Force a full redraw when the screen contents are invalid. */ 700256145Sray if (vd->vd_flags & VDF_INVALID) { 701219888Sed tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0; 702219888Sed tarea.tr_end = size; 703219888Sed tmask.vbm_row = tmask.vbm_col = VBM_DIRTY; 704219888Sed 705219888Sed vd->vd_flags &= ~VDF_INVALID; 706219888Sed } 707219888Sed 708258327Sray if ((vw->vw_flags & VWF_MOUSE_HIDE) == 0) { 709258327Sray /* Mark last mouse position as dirty to erase. */ 710258327Sray vtbuf_mouse_cursor_position(&vw->vw_buf, vd->vd_mdirtyx, 711258327Sray vd->vd_mdirtyy); 712258327Sray } 713257981Sray 714219888Sed for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) { 715219888Sed if (!VTBUF_DIRTYROW(&tmask, row)) 716219888Sed continue; 717256145Sray r = VTBUF_GET_ROW(&vw->vw_buf, row); 718219888Sed for (col = tarea.tr_begin.tp_col; 719219888Sed col < tarea.tr_end.tp_col; col++) { 720219888Sed if (!VTBUF_DIRTYCOL(&tmask, col)) 721219888Sed continue; 722219888Sed 723256145Sray vt_bitblt_char(vd, vf, r[col], 724256903Sray VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col); 725219888Sed } 726219888Sed } 727257981Sray 728258327Sray /* Mouse disabled. */ 729258327Sray if (vw->vw_flags & VWF_MOUSE_HIDE) 730258327Sray return; 731258327Sray 732258110Sray /* No mouse for DDB. */ 733258110Sray if (kdb_active || panicstr != NULL) 734258110Sray return; 735258110Sray 736257981Sray if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) == 737257981Sray VDF_MOUSECURSOR) { 738257981Sray m = &vt_default_mouse_pointer; 739257988Sray bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */ 740257981Sray w = m->w; 741257981Sray h = m->h; 742257981Sray 743257981Sray if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width)) 744257981Sray w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1; 745257981Sray if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height)) 746257981Sray h = (size.tp_row * vf->vf_height) - vd->vd_my - 1; 747257981Sray 748257988Sray vd->vd_driver->vd_bitbltchr(vd, m->map, m->mask, bpl, 749257981Sray vd->vd_offset.tp_row + vd->vd_my, 750257981Sray vd->vd_offset.tp_col + vd->vd_mx, 751257981Sray w, h, TC_WHITE, TC_BLACK); 752257981Sray /* Save point of last mouse cursor to erase it later. */ 753257981Sray vd->vd_mdirtyx = vd->vd_mx / vf->vf_width; 754257981Sray vd->vd_mdirtyy = vd->vd_my / vf->vf_height; 755257981Sray } 756219888Sed} 757219888Sed 758219888Sedstatic void 759219888Sedvt_timer(void *arg) 760219888Sed{ 761257387Sray struct vt_device *vd; 762219888Sed 763257387Sray vd = arg; 764257387Sray /* Update screen if required. */ 765219888Sed vt_flush(vd); 766257387Sray /* Schedule for next update. */ 767219888Sed callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 768219888Sed} 769219888Sed 770219888Sedstatic void 771219888Sedvtterm_done(struct terminal *tm) 772219888Sed{ 773219888Sed struct vt_window *vw = tm->tm_softc; 774219888Sed struct vt_device *vd = vw->vw_device; 775219888Sed 776219888Sed if (kdb_active || panicstr != NULL) { 777219888Sed /* Switch to the debugger. */ 778219888Sed if (vd->vd_curwindow != vw) { 779219888Sed vd->vd_curwindow = vw; 780219888Sed vd->vd_flags |= VDF_INVALID; 781257626Sray if (vd->vd_driver->vd_postswitch) 782257626Sray vd->vd_driver->vd_postswitch(vd); 783219888Sed } 784219888Sed vd->vd_flags &= ~VDF_SPLASH; 785219888Sed vt_flush(vd); 786219888Sed } else if (!(vd->vd_flags & VDF_ASYNC)) { 787219888Sed vt_flush(vd); 788219888Sed } 789219888Sed} 790219888Sed 791219888Sedstatic void 792256145Srayvtterm_splash(struct vt_device *vd) 793256145Sray{ 794256145Sray vt_axis_t top, left; 795256145Sray 796256145Sray /* Display a nice boot splash. */ 797257722Sray if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) { 798256145Sray 799256145Sray top = (vd->vd_height - vt_logo_height) / 2; 800256145Sray left = (vd->vd_width - vt_logo_width) / 2; 801256145Sray switch (vt_logo_depth) { 802256145Sray case 1: 803256145Sray /* XXX: Unhardcode colors! */ 804257988Sray vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0, 805257988Sray top, left, vt_logo_width, vt_logo_height, 0xf, 0x0); 806256145Sray } 807256145Sray vd->vd_flags |= VDF_SPLASH; 808256145Sray } 809256145Sray} 810256145Sray 811256145Sraystatic void 812219888Sedvtterm_cnprobe(struct terminal *tm, struct consdev *cp) 813219888Sed{ 814219888Sed struct vt_window *vw = tm->tm_softc; 815219888Sed struct vt_device *vd = vw->vw_device; 816219888Sed struct winsize wsz; 817219888Sed 818256145Sray if (vd->vd_flags & VDF_INITIALIZED) 819256145Sray /* Initialization already done. */ 820256145Sray return; 821256145Sray 822219888Sed cp->cn_pri = vd->vd_driver->vd_init(vd); 823219888Sed if (cp->cn_pri == CN_DEAD) { 824219888Sed vd->vd_flags |= VDF_DEAD; 825219888Sed return; 826219888Sed } 827219888Sed 828230469Snwhitehorn /* Initialize any early-boot keyboard drivers */ 829230469Snwhitehorn kbd_configure(KB_CONF_PROBE_ONLY); 830230469Snwhitehorn 831219888Sed vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 832256145Sray vd->vd_windows[VT_CONSWINDOW] = vw; 833219888Sed sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 834219888Sed 835219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 836219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 837219888Sed 838219888Sed vtbuf_init_early(&vw->vw_buf); 839219888Sed vt_winsize(vd, vw->vw_font, &wsz); 840219888Sed terminal_set_winsize(tm, &wsz); 841219888Sed 842256145Sray vtterm_splash(vd); 843219888Sed 844256145Sray vd->vd_flags |= VDF_INITIALIZED; 845256145Sray main_vd = vd; 846219888Sed} 847219888Sed 848219888Sedstatic int 849219888Sedvtterm_cngetc(struct terminal *tm) 850219888Sed{ 851219888Sed struct vt_window *vw = tm->tm_softc; 852219888Sed struct vt_device *vd = vw->vw_device; 853219888Sed keyboard_t *kbd; 854257076Sray int state; 855219888Sed u_int c; 856219888Sed 857257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 858257076Sray return (*vw->vw_kbdsq++); 859257076Sray 860257076Sray state = 0; 861219888Sed /* Make sure the splash screen is not there. */ 862219888Sed if (vd->vd_flags & VDF_SPLASH) { 863256145Sray /* Remove splash */ 864219888Sed vd->vd_flags &= ~VDF_SPLASH; 865256145Sray /* Mark screen as invalid to force update */ 866256145Sray vd->vd_flags |= VDF_INVALID; 867219888Sed vt_flush(vd); 868219888Sed } 869219888Sed 870219888Sed /* Stripped down keyboard handler. */ 871219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 872219888Sed if (kbd == NULL) 873219888Sed return (-1); 874219888Sed 875256145Sray /* Force keyboard input mode to K_XLATE */ 876256145Sray c = K_XLATE; 877256145Sray kbdd_ioctl(kbd, KDSKBMODE, (void *)&c); 878256145Sray 879219888Sed /* Switch the keyboard to polling to make it work here. */ 880219888Sed kbdd_poll(kbd, TRUE); 881219888Sed c = kbdd_read_char(kbd, 0); 882219888Sed kbdd_poll(kbd, FALSE); 883219888Sed if (c & RELKEY) 884219888Sed return (-1); 885256145Sray 886257076Sray if (vw->vw_flags & VWF_SCROLL) { 887257076Sray vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 888257076Sray vt_flush(vd); 889257076Sray return (-1); 890257076Sray } 891257076Sray 892219888Sed /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 893219888Sed if (c & SPCLKEY) { 894219888Sed switch (c) { 895257076Sray case SPCLKEY | SLK: 896219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 897219888Sed if (state & SLKED) { 898219888Sed /* Turn scrolling on. */ 899258408Sray vw->vw_flags |= VWF_SCROLL; 900256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 901219888Sed } else { 902219888Sed /* Turn scrolling off. */ 903257076Sray vt_scroll(vw, 0, VHS_END); 904258408Sray vw->vw_flags &= ~VWF_SCROLL; 905256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 906219888Sed } 907219888Sed break; 908257076Sray /* XXX: KDB can handle history. */ 909257076Sray case SPCLKEY | FKEY | F(50): /* Arrow up. */ 910257076Sray vw->vw_kbdsq = "\x1b[A"; 911219888Sed break; 912257076Sray case SPCLKEY | FKEY | F(58): /* Arrow down. */ 913257076Sray vw->vw_kbdsq = "\x1b[B"; 914219888Sed break; 915257076Sray case SPCLKEY | FKEY | F(55): /* Arrow right. */ 916257076Sray vw->vw_kbdsq = "\x1b[C"; 917219888Sed break; 918257076Sray case SPCLKEY | FKEY | F(53): /* Arrow left. */ 919257076Sray vw->vw_kbdsq = "\x1b[D"; 920219888Sed break; 921219888Sed } 922219888Sed 923219888Sed /* Force refresh to make scrollback work. */ 924219888Sed vt_flush(vd); 925219888Sed } else if (KEYFLAGS(c) == 0) { 926219888Sed return KEYCHAR(c); 927219888Sed } 928256145Sray 929257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 930258166Sray return (*vw->vw_kbdsq++); 931257076Sray 932219888Sed return (-1); 933219888Sed} 934219888Sed 935219888Sedstatic void 936219888Sedvtterm_opened(struct terminal *tm, int opened) 937219888Sed{ 938219888Sed struct vt_window *vw = tm->tm_softc; 939219888Sed struct vt_device *vd = vw->vw_device; 940219888Sed 941219888Sed VT_LOCK(vd); 942219888Sed vd->vd_flags &= ~VDF_SPLASH; 943219888Sed if (opened) 944258408Sray vw->vw_flags |= VWF_OPENED; 945256145Sray else { 946258408Sray vw->vw_flags &= ~VWF_OPENED; 947256145Sray /* TODO: finish ACQ/REL */ 948256145Sray } 949219888Sed VT_UNLOCK(vd); 950219888Sed} 951219888Sed 952219888Sedstatic int 953219888Sedvt_change_font(struct vt_window *vw, struct vt_font *vf) 954219888Sed{ 955219888Sed struct vt_device *vd = vw->vw_device; 956219888Sed struct terminal *tm = vw->vw_terminal; 957219888Sed term_pos_t size; 958219888Sed struct winsize wsz; 959219888Sed 960219888Sed /* 961219888Sed * Changing fonts. 962219888Sed * 963219888Sed * Changing fonts is a little tricky. We must prevent 964219888Sed * simultaneous access to the device, so we must stop 965219888Sed * the display timer and the terminal from accessing. 966219888Sed * We need to switch fonts and grow our screen buffer. 967219888Sed * 968219888Sed * XXX: Right now the code uses terminal_mute() to 969219888Sed * prevent data from reaching the console driver while 970219888Sed * resizing the screen buffer. This isn't elegant... 971219888Sed */ 972219888Sed 973219888Sed VT_LOCK(vd); 974219888Sed if (vw->vw_flags & VWF_BUSY) { 975219888Sed /* Another process is changing the font. */ 976219888Sed VT_UNLOCK(vd); 977219888Sed return (EBUSY); 978219888Sed } 979219888Sed if (vw->vw_font == NULL) { 980219888Sed /* Our device doesn't need fonts. */ 981219888Sed VT_UNLOCK(vd); 982219888Sed return (ENOTTY); 983219888Sed } 984258408Sray vw->vw_flags |= VWF_BUSY; 985219888Sed VT_UNLOCK(vd); 986219888Sed 987219888Sed vt_termsize(vd, vf, &size); 988219888Sed vt_winsize(vd, vf, &wsz); 989257978Sray /* Save offset to font aligned area. */ 990257978Sray vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2; 991257978Sray vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2; 992219888Sed 993219888Sed /* Grow the screen buffer and terminal. */ 994219888Sed terminal_mute(tm, 1); 995256145Sray vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 996256903Sray terminal_set_winsize_blank(tm, &wsz, 0); 997219888Sed terminal_mute(tm, 0); 998219888Sed 999219888Sed /* Actually apply the font to the current window. */ 1000219888Sed VT_LOCK(vd); 1001219888Sed vtfont_unref(vw->vw_font); 1002219888Sed vw->vw_font = vtfont_ref(vf); 1003219888Sed 1004219888Sed /* Force a full redraw the next timer tick. */ 1005219888Sed if (vd->vd_curwindow == vw) 1006219888Sed vd->vd_flags |= VDF_INVALID; 1007258408Sray vw->vw_flags &= ~VWF_BUSY; 1008219888Sed VT_UNLOCK(vd); 1009219888Sed return (0); 1010219888Sed} 1011219888Sed 1012219888Sedstatic int 1013256145Srayvt_proc_alive(struct vt_window *vw) 1014256145Sray{ 1015256145Sray struct proc *p; 1016256145Sray 1017256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1018256145Sray return FALSE; 1019256145Sray 1020256145Sray if (vw->vw_proc) { 1021256145Sray if ((p = pfind(vw->vw_pid)) != NULL) 1022256145Sray PROC_UNLOCK(p); 1023256145Sray if (vw->vw_proc == p) 1024256145Sray return TRUE; 1025256145Sray vw->vw_proc = NULL; 1026256145Sray vw->vw_smode.mode = VT_AUTO; 1027256145Sray DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 1028256145Sray vw->vw_pid = 0; 1029256145Sray } 1030256145Sray return FALSE; 1031256145Sray} 1032256145Sray 1033256145Sraystatic int 1034256145Sraysignal_vt_rel(struct vt_window *vw) 1035256145Sray{ 1036257815Sray 1037256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1038256145Sray return FALSE; 1039256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1040256145Sray vw->vw_proc = NULL; 1041256145Sray vw->vw_pid = 0; 1042256145Sray return TRUE; 1043256145Sray } 1044258408Sray vw->vw_flags |= VWF_SWWAIT_REL; 1045256145Sray PROC_LOCK(vw->vw_proc); 1046256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 1047256145Sray PROC_UNLOCK(vw->vw_proc); 1048256145Sray DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 1049256145Sray return TRUE; 1050256145Sray} 1051256145Sray 1052256145Sraystatic int 1053256145Sraysignal_vt_acq(struct vt_window *vw) 1054256145Sray{ 1055257815Sray 1056256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1057256145Sray return FALSE; 1058256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1059256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1060256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1061256145Sray vw->vw_proc = NULL; 1062256145Sray vw->vw_pid = 0; 1063256145Sray return TRUE; 1064256145Sray } 1065258408Sray vw->vw_flags |= VWF_SWWAIT_ACQ; 1066256145Sray PROC_LOCK(vw->vw_proc); 1067256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1068256145Sray PROC_UNLOCK(vw->vw_proc); 1069256145Sray DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1070256145Sray return TRUE; 1071256145Sray} 1072256145Sray 1073256145Sraystatic int 1074256145Srayfinish_vt_rel(struct vt_window *vw, int release, int *s) 1075256145Sray{ 1076257815Sray 1077256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1078258408Sray vw->vw_flags &= ~VWF_SWWAIT_REL; 1079256145Sray if (release) { 1080256145Sray callout_drain(&vw->vw_proc_dead_timer); 1081256145Sray vt_late_window_switch(vw->vw_switch_to); 1082256145Sray } 1083256145Sray return 0; 1084256145Sray } 1085256145Sray return EINVAL; 1086256145Sray} 1087256145Sray 1088256145Sraystatic int 1089256145Srayfinish_vt_acq(struct vt_window *vw) 1090256145Sray{ 1091257815Sray 1092256145Sray if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1093258408Sray vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1094256145Sray return 0; 1095256145Sray } 1096256145Sray return EINVAL; 1097256145Sray} 1098256145Sray 1099257977Srayvoid 1100257977Srayvt_mouse_event(int type, int x, int y, int event, int cnt) 1101257977Sray{ 1102257977Sray struct vt_device *vd; 1103257977Sray struct vt_window *vw; 1104257977Sray struct vt_font *vf; 1105257977Sray term_pos_t size; 1106258090Sray term_char_t *buf; 1107258090Sray int i, len, mark; 1108257977Sray 1109257977Sray vd = main_vd; 1110257977Sray vw = vd->vd_curwindow; 1111257977Sray vf = vw->vw_font; 1112258781Snwhitehorn mark = 0; 1113257977Sray 1114258327Sray if (vw->vw_flags & VWF_MOUSE_HIDE) 1115258327Sray return; /* Mouse disabled. */ 1116258327Sray 1117257977Sray if (vf == NULL) /* Text mode. */ 1118257977Sray return; 1119257977Sray 1120257977Sray /* 1121257977Sray * TODO: add flag about pointer position changed, to not redraw chars 1122257977Sray * under mouse pointer when nothing changed. 1123257977Sray */ 1124257977Sray 1125257977Sray switch (type) { 1126257977Sray case MOUSE_ACTION: 1127257977Sray case MOUSE_MOTION_EVENT: 1128257977Sray /* Movement */ 1129257977Sray x += vd->vd_mx; 1130257977Sray y += vd->vd_my; 1131257977Sray 1132257977Sray vt_termsize(vd, vf, &size); 1133257977Sray 1134257977Sray /* Apply limits. */ 1135257977Sray x = MAX(x, 0); 1136257977Sray y = MAX(y, 0); 1137257977Sray x = MIN(x, (size.tp_col * vf->vf_width) - 1); 1138257977Sray y = MIN(y, (size.tp_row * vf->vf_height) - 1); 1139257977Sray 1140257977Sray vd->vd_mx = x; 1141257977Sray vd->vd_my = y; 1142258090Sray if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) && 1143258130Sray (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE, 1144258090Sray vd->vd_mx / vf->vf_width, 1145258090Sray vd->vd_my / vf->vf_height) == 1)) { 1146258090Sray 1147258090Sray /* 1148258090Sray * We have something marked to copy, so update pointer 1149258090Sray * to window with selection. 1150258090Sray */ 1151258090Sray vd->vd_markedwin = vw; 1152258090Sray } 1153257977Sray return; /* Done */ 1154257977Sray case MOUSE_BUTTON_EVENT: 1155257977Sray /* Buttons */ 1156257977Sray break; 1157257977Sray default: 1158257977Sray return; /* Done */ 1159257977Sray } 1160257977Sray 1161257977Sray switch (event) { 1162257977Sray case MOUSE_BUTTON1DOWN: 1163257977Sray switch (cnt % 4) { 1164257977Sray case 0: /* up */ 1165257977Sray mark = VTB_MARK_END; 1166257977Sray break; 1167257977Sray case 1: /* single click: start cut operation */ 1168257977Sray mark = VTB_MARK_START; 1169257977Sray break; 1170257977Sray case 2: /* double click: cut a word */ 1171257977Sray mark = VTB_MARK_WORD; 1172257977Sray break; 1173257977Sray case 3: /* triple click: cut a line */ 1174257977Sray mark = VTB_MARK_ROW; 1175257977Sray break; 1176257977Sray } 1177257977Sray break; 1178257977Sray case VT_MOUSE_PASTEBUTTON: 1179258112Sray switch (cnt) { 1180257977Sray case 0: /* up */ 1181257977Sray break; 1182257977Sray default: 1183258090Sray if (vd->vd_markedwin == NULL) 1184258090Sray return; 1185258090Sray /* Get current selecton size in bytes. */ 1186258090Sray len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf); 1187258090Sray if (len <= 0) 1188258090Sray return; 1189258090Sray 1190258090Sray buf = malloc(len, M_VT, M_WAITOK | M_ZERO); 1191258090Sray /* Request cupy/paste buffer data, no more than `len' */ 1192258090Sray vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf, 1193258090Sray len); 1194258090Sray 1195258090Sray len /= sizeof(term_char_t); 1196258090Sray for (i = 0; i < len; i++ ) { 1197258090Sray if (buf[i] == '\0') 1198258090Sray continue; 1199258090Sray terminal_input_char(vw->vw_terminal, buf[i]); 1200258090Sray } 1201258090Sray 1202258090Sray /* Done, so cleanup. */ 1203258090Sray free(buf, M_VT); 1204257977Sray break; 1205257977Sray } 1206257977Sray return; /* Done */ 1207257977Sray case VT_MOUSE_EXTENDBUTTON: 1208258112Sray switch (cnt) { 1209257977Sray case 0: /* up */ 1210257977Sray if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 1211258130Sray mark = VTB_MARK_EXTEND; 1212257977Sray else 1213257977Sray mark = 0; 1214257977Sray break; 1215257977Sray default: 1216257977Sray mark = VTB_MARK_EXTEND; 1217257977Sray break; 1218257977Sray } 1219257977Sray break; 1220257977Sray default: 1221257977Sray return; /* Done */ 1222257977Sray } 1223257977Sray 1224257977Sray /* Save buttons state. */ 1225257977Sray if (cnt > 0) 1226257977Sray vd->vd_mstate |= event; 1227257977Sray else 1228257977Sray vd->vd_mstate &= ~event; 1229257977Sray 1230258090Sray if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 1231258090Sray vd->vd_my / vf->vf_height) == 1) { 1232258090Sray /* 1233258090Sray * We have something marked to copy, so update pointer to 1234258090Sray * window with selection. 1235258090Sray */ 1236258090Sray vd->vd_markedwin = vw; 1237258090Sray } 1238257977Sray} 1239257977Sray 1240258327Srayvoid 1241258327Srayvt_mouse_state(int show) 1242258327Sray{ 1243258327Sray struct vt_device *vd; 1244258327Sray struct vt_window *vw; 1245258327Sray 1246258327Sray vd = main_vd; 1247258327Sray vw = vd->vd_curwindow; 1248258327Sray 1249258327Sray switch (show) { 1250258327Sray case VT_MOUSE_HIDE: 1251258409Sray vw->vw_flags |= VWF_MOUSE_HIDE; 1252258327Sray break; 1253258327Sray case VT_MOUSE_SHOW: 1254258409Sray vw->vw_flags &= ~VWF_MOUSE_HIDE; 1255258327Sray break; 1256258327Sray } 1257258327Sray} 1258258327Sray 1259256145Sraystatic int 1260219888Sedvtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1261219888Sed struct thread *td) 1262219888Sed{ 1263219888Sed struct vt_window *vw = tm->tm_softc; 1264219888Sed struct vt_device *vd = vw->vw_device; 1265256145Sray int error, s; 1266219888Sed 1267219888Sed switch (cmd) { 1268219888Sed case GIO_KEYMAP: 1269219888Sed case PIO_KEYMAP: 1270219888Sed case GIO_DEADKEYMAP: 1271219888Sed case PIO_DEADKEYMAP: 1272219888Sed case GETFKEY: 1273219888Sed case SETFKEY: 1274219888Sed case KDGKBINFO: { 1275219888Sed keyboard_t *kbd; 1276256145Sray error = 0; 1277219888Sed 1278219888Sed mtx_lock(&Giant); 1279219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1280219888Sed if (kbd != NULL) 1281219888Sed error = kbdd_ioctl(kbd, cmd, data); 1282219888Sed mtx_unlock(&Giant); 1283219888Sed if (error == ENOIOCTL) 1284219888Sed return (ENODEV); 1285219888Sed return (error); 1286219888Sed } 1287256145Sray case KDGKBMODE: { 1288256145Sray int mode = -1; 1289256145Sray keyboard_t *kbd; 1290256145Sray 1291256145Sray mtx_lock(&Giant); 1292256145Sray kbd = kbd_get_keyboard(vd->vd_keyboard); 1293256145Sray if (kbd != NULL) { 1294256145Sray kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1295256145Sray } 1296256145Sray mtx_unlock(&Giant); 1297256145Sray DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1298256145Sray *(int *)data = mode; 1299256145Sray return (0); 1300256145Sray } 1301219888Sed case KDSKBMODE: { 1302219888Sed int mode; 1303219888Sed 1304219888Sed mode = *(int *)data; 1305219888Sed switch (mode) { 1306219888Sed case K_XLATE: 1307219888Sed case K_RAW: 1308219888Sed case K_CODE: 1309219888Sed vw->vw_kbdmode = mode; 1310219888Sed if (vw == vd->vd_curwindow) { 1311219888Sed keyboard_t *kbd; 1312256145Sray error = 0; 1313219888Sed 1314257983Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, 1315257983Sray vd->vd_keyboard); 1316219888Sed mtx_lock(&Giant); 1317219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1318256145Sray if (kbd != NULL) { 1319256145Sray DPRINTF(20, "kbdd_ioctl(KDSKBMODE, %d)\n", mode); 1320256145Sray error = kbdd_ioctl(kbd, KDSKBMODE, 1321219888Sed (void *)&mode); 1322256145Sray } 1323219888Sed mtx_unlock(&Giant); 1324256145Sray if (error) 1325257983Sray DPRINTF(20, "kbdd_ioctl(KDSKBMODE) " 1326257983Sray "return %d\n", error); 1327219888Sed } 1328219888Sed return (0); 1329219888Sed default: 1330219888Sed return (EINVAL); 1331219888Sed } 1332219888Sed } 1333219888Sed case CONS_BLANKTIME: 1334219888Sed /* XXX */ 1335219888Sed return (0); 1336219888Sed case CONS_GET: 1337219888Sed /* XXX */ 1338219888Sed *(int *)data = M_CG640x480; 1339219888Sed return (0); 1340219888Sed case CONS_GETINFO: { 1341219888Sed vid_info_t *vi = (vid_info_t *)data; 1342219888Sed 1343219888Sed vi->m_num = vd->vd_curwindow->vw_number + 1; 1344219888Sed /* XXX: other fields! */ 1345219888Sed return (0); 1346219888Sed } 1347219888Sed case CONS_GETVERS: 1348219888Sed *(int *)data = 0x200; 1349219888Sed return 0; 1350219888Sed case CONS_MODEINFO: 1351219888Sed /* XXX */ 1352219888Sed return (0); 1353219888Sed case CONS_MOUSECTL: { 1354219888Sed mouse_info_t *mouse = (mouse_info_t*)data; 1355219888Sed 1356219888Sed /* 1357219888Sed * This has no effect on vt(4). We don't draw any mouse 1358219888Sed * cursor. Just ignore MOUSE_HIDE and MOUSE_SHOW to 1359219888Sed * prevent excessive errors. All the other commands 1360219888Sed * should not be applied to individual TTYs, but only to 1361219888Sed * consolectl. 1362219888Sed */ 1363219888Sed switch (mouse->operation) { 1364219888Sed case MOUSE_HIDE: 1365257982Sray vd->vd_flags &= ~VDF_MOUSECURSOR; 1366257982Sray return (0); 1367219888Sed case MOUSE_SHOW: 1368257982Sray vd->vd_mx = vd->vd_width / 2; 1369257982Sray vd->vd_my = vd->vd_height / 2; 1370257982Sray vd->vd_flags |= VDF_MOUSECURSOR; 1371219888Sed return (0); 1372219888Sed default: 1373219888Sed return (EINVAL); 1374219888Sed } 1375219888Sed } 1376219888Sed case PIO_VFONT: { 1377219888Sed struct vt_font *vf; 1378219888Sed 1379219888Sed error = vtfont_load((void *)data, &vf); 1380219888Sed if (error != 0) 1381219888Sed return (error); 1382219888Sed 1383219888Sed error = vt_change_font(vw, vf); 1384219888Sed vtfont_unref(vf); 1385219888Sed return (error); 1386219888Sed } 1387219888Sed case GIO_SCRNMAP: { 1388219888Sed scrmap_t *sm = (scrmap_t *)data; 1389219888Sed int i; 1390219888Sed 1391219888Sed /* We don't have screen maps, so return a handcrafted one. */ 1392219888Sed for (i = 0; i < 256; i++) 1393219888Sed sm->scrmap[i] = i; 1394219888Sed return (0); 1395219888Sed } 1396219888Sed case KDGETLED: 1397219888Sed /* XXX */ 1398219888Sed return (0); 1399219888Sed case KDSETLED: 1400219888Sed /* XXX */ 1401219888Sed return (0); 1402219888Sed case KDSETMODE: 1403219888Sed /* XXX */ 1404219888Sed return (0); 1405219888Sed case KDSETRAD: 1406219888Sed /* XXX */ 1407219888Sed return (0); 1408256145Sray case VT_ACTIVATE: { 1409256145Sray int win; 1410256145Sray win = *(int *)data - 1; 1411256145Sray DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, VT_UNIT(vw), win); 1412256145Sray if ((win > VT_MAXWINDOWS) || (win < 0)) 1413256145Sray return (EINVAL); 1414256145Sray return (vt_proc_window_switch(vd->vd_windows[win])); 1415256145Sray } 1416219888Sed case VT_GETACTIVE: 1417219888Sed *(int *)data = vd->vd_curwindow->vw_number + 1; 1418219888Sed return (0); 1419219888Sed case VT_GETINDEX: 1420219888Sed *(int *)data = vw->vw_number + 1; 1421219888Sed return (0); 1422256145Sray case VT_LOCKSWITCH: 1423256145Sray /* TODO: Check current state, switching can be in progress. */ 1424256145Sray if ((*(int *)data) & 0x01) 1425258408Sray vw->vw_flags |= VWF_VTYLOCK; 1426256145Sray else 1427258408Sray vw->vw_flags &= ~VWF_VTYLOCK; 1428219888Sed case VT_OPENQRY: { 1429219888Sed unsigned int i; 1430219888Sed 1431219888Sed VT_LOCK(vd); 1432219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1433219888Sed vw = vd->vd_windows[i]; 1434219888Sed if (vw == NULL) 1435219888Sed continue; 1436219888Sed if (!(vw->vw_flags & VWF_OPENED)) { 1437219888Sed *(int *)data = vw->vw_number + 1; 1438219888Sed VT_UNLOCK(vd); 1439219888Sed return (0); 1440219888Sed } 1441219888Sed } 1442219888Sed VT_UNLOCK(vd); 1443219888Sed return (EINVAL); 1444219888Sed } 1445219888Sed case VT_WAITACTIVE: { 1446219888Sed unsigned int i; 1447256145Sray error = 0; 1448219888Sed 1449219888Sed i = *(unsigned int *)data; 1450219888Sed if (i > VT_MAXWINDOWS) 1451219888Sed return (EINVAL); 1452219888Sed if (i != 0) 1453219888Sed vw = vd->vd_windows[i - 1]; 1454219888Sed 1455219888Sed VT_LOCK(vd); 1456219888Sed while (vd->vd_curwindow != vw && error == 0) 1457219888Sed error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 1458219888Sed VT_UNLOCK(vd); 1459219888Sed return (error); 1460219888Sed } 1461256145Sray case VT_SETMODE: /* set screen switcher mode */ 1462256145Sray { 1463256145Sray struct vt_mode *mode; 1464256145Sray struct proc *p1; 1465256145Sray 1466256145Sray mode = (struct vt_mode *)data; 1467256145Sray DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 1468256145Sray if (vw->vw_smode.mode == VT_PROCESS) { 1469256145Sray p1 = pfind(vw->vw_pid); 1470256145Sray if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 1471256145Sray if (p1) 1472256145Sray PROC_UNLOCK(p1); 1473256145Sray DPRINTF(5, "error EPERM\n"); 1474256145Sray return (EPERM); 1475256145Sray } 1476256145Sray if (p1) 1477256145Sray PROC_UNLOCK(p1); 1478256145Sray } 1479256145Sray if (mode->mode == VT_AUTO) { 1480256145Sray vw->vw_smode.mode = VT_AUTO; 1481256145Sray vw->vw_proc = NULL; 1482256145Sray vw->vw_pid = 0; 1483256145Sray DPRINTF(5, "VT_AUTO, "); 1484256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1485256145Sray cnavailable(vw->vw_terminal->consdev, TRUE); 1486256145Sray /* were we in the middle of the vty switching process? */ 1487256145Sray if (finish_vt_rel(vw, TRUE, &s) == 0) 1488256145Sray DPRINTF(5, "reset WAIT_REL, "); 1489256145Sray if (finish_vt_acq(vw) == 0) 1490256145Sray DPRINTF(5, "reset WAIT_ACQ, "); 1491256145Sray return (0); 1492256145Sray } else if (mode->mode == VT_PROCESS) { 1493256145Sray if (!ISSIGVALID(mode->relsig) || 1494256145Sray !ISSIGVALID(mode->acqsig) || 1495256145Sray !ISSIGVALID(mode->frsig)) { 1496256145Sray DPRINTF(5, "error EINVAL\n"); 1497256145Sray return (EINVAL); 1498256145Sray } 1499256145Sray DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 1500256145Sray bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 1501256145Sray vw->vw_proc = td->td_proc; 1502256145Sray vw->vw_pid = vw->vw_proc->p_pid; 1503256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1504256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1505256145Sray } else { 1506256145Sray DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 1507256145Sray mode->mode); 1508256145Sray return (EINVAL); 1509256145Sray } 1510256145Sray DPRINTF(5, "\n"); 1511256145Sray return 0; 1512219888Sed } 1513219888Sed 1514256145Sray case VT_GETMODE: /* get screen switcher mode */ 1515256145Sray bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 1516256145Sray return 0; 1517256145Sray 1518256145Sray case VT_RELDISP: /* screen switcher ioctl */ 1519256145Sray /* 1520256145Sray * This must be the current vty which is in the VT_PROCESS 1521256145Sray * switching mode... 1522256145Sray */ 1523256145Sray if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 1524256145Sray VT_PROCESS)) { 1525256145Sray return EINVAL; 1526256145Sray } 1527256145Sray /* ...and this process is controlling it. */ 1528256145Sray if (vw->vw_proc != td->td_proc) { 1529256145Sray return EPERM; 1530256145Sray } 1531256145Sray error = EINVAL; 1532256145Sray switch(*(int *)data) { 1533256145Sray case VT_FALSE: /* user refuses to release screen, abort */ 1534256145Sray if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 1535256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", SC_DRIVER_NAME, 1536256145Sray VT_UNIT(vw)); 1537256145Sray break; 1538256145Sray case VT_TRUE: /* user has released screen, go on */ 1539256145Sray /* finish_vt_rel(..., TRUE, ...) should not be locked */ 1540256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1541256145Sray if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 1542256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 1543256145Sray SC_DRIVER_NAME, VT_UNIT(vw)); 1544256145Sray } else { 1545256145Sray error = EINVAL; 1546256145Sray } 1547256145Sray return (error); 1548256145Sray case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1549256145Sray if ((error = finish_vt_acq(vw)) == 0) 1550256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", SC_DRIVER_NAME, 1551256145Sray VT_UNIT(vw)); 1552256145Sray break; 1553256145Sray default: 1554256145Sray break; 1555256145Sray } 1556256145Sray return error; 1557256145Sray } 1558256145Sray 1559219888Sed return (ENOIOCTL); 1560219888Sed} 1561219888Sed 1562219888Sedstatic struct vt_window * 1563219888Sedvt_allocate_window(struct vt_device *vd, unsigned int window) 1564219888Sed{ 1565219888Sed struct vt_window *vw; 1566219888Sed struct terminal *tm; 1567219888Sed term_pos_t size; 1568219888Sed struct winsize wsz; 1569219888Sed 1570219888Sed vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 1571219888Sed vw->vw_device = vd; 1572219888Sed vw->vw_number = window; 1573219888Sed vw->vw_kbdmode = K_XLATE; 1574219888Sed 1575219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 1576219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 1577256145Sray 1578219888Sed vt_termsize(vd, vw->vw_font, &size); 1579219888Sed vt_winsize(vd, vw->vw_font, &wsz); 1580219888Sed vtbuf_init(&vw->vw_buf, &size); 1581219888Sed 1582219888Sed tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 1583219888Sed terminal_set_winsize(tm, &wsz); 1584219888Sed vd->vd_windows[window] = vw; 1585256145Sray callout_init(&vw->vw_proc_dead_timer, 0); 1586219888Sed 1587219888Sed return (vw); 1588219888Sed} 1589219888Sed 1590219888Sedvoid 1591219888Sedvt_upgrade(struct vt_device *vd) 1592219888Sed{ 1593219888Sed struct vt_window *vw; 1594219888Sed unsigned int i; 1595219888Sed 1596256145Sray /* Device didn't pass vd_init() or already upgraded. */ 1597256145Sray if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD)) 1598219888Sed return; 1599256145Sray vd->vd_flags |= VDF_ASYNC; 1600219888Sed 1601219888Sed mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); 1602219888Sed cv_init(&vd->vd_winswitch, "vtwswt"); 1603219888Sed 1604256145Sray /* Init 25 Hz timer. */ 1605219888Sed callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 1606219888Sed 1607219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1608219888Sed vw = vd->vd_windows[i]; 1609219888Sed if (vw == NULL) { 1610219888Sed /* New window. */ 1611219888Sed vw = vt_allocate_window(vd, i); 1612256145Sray } 1613256145Sray if (i == VT_CONSWINDOW) { 1614219888Sed /* Console window. */ 1615219888Sed EVENTHANDLER_REGISTER(shutdown_pre_sync, 1616219888Sed vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 1617219888Sed } 1618219888Sed terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 1619219888Sed } 1620256145Sray if (vd->vd_curwindow == NULL) 1621256145Sray vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 1622219888Sed 1623219888Sed /* Attach keyboard. */ 1624219888Sed vt_allocate_keyboard(vd); 1625256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 1626256145Sray 1627256145Sray /* Start timer when everything ready. */ 1628256145Sray callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 1629219888Sed} 1630219888Sed 1631256145Sraystatic void 1632256145Srayvt_resize(struct vt_device *vd) 1633256145Sray{ 1634256145Sray struct vt_window *vw; 1635256145Sray int i; 1636256145Sray 1637256145Sray for (i = 0; i < VT_MAXWINDOWS; i++) { 1638256145Sray vw = vd->vd_windows[i]; 1639256145Sray /* Resize terminal windows */ 1640256145Sray vt_change_font(vw, vw->vw_font); 1641256145Sray } 1642256145Sray} 1643256145Sray 1644219888Sedvoid 1645219888Sedvt_allocate(struct vt_driver *drv, void *softc) 1646219888Sed{ 1647219888Sed struct vt_device *vd; 1648256903Sray struct winsize wsz; 1649219888Sed 1650256145Sray if (main_vd == NULL) { 1651256145Sray main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); 1652256903Sray printf("%s: VT initialize with new VT driver.\n", __func__); 1653256145Sray } else { 1654256145Sray /* 1655256145Sray * Check if have rights to replace current driver. For example: 1656256145Sray * it is bad idea to replace KMS driver with generic VGA one. 1657256145Sray */ 1658256903Sray if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 1659256903Sray printf("%s: Driver priority %d too low. Current %d\n ", 1660256903Sray __func__, drv->vd_priority, 1661256903Sray main_vd->vd_driver->vd_priority); 1662256145Sray return; 1663256903Sray } 1664256903Sray printf("%s: Replace existing VT driver.\n", __func__); 1665256145Sray } 1666256145Sray vd = main_vd; 1667256145Sray 1668256527Sray /* Stop vt_flush periodic task. */ 1669256145Sray if (vd->vd_curwindow != NULL) 1670256145Sray callout_drain(&vd->vd_timer); 1671256145Sray 1672219888Sed vd->vd_driver = drv; 1673219888Sed vd->vd_softc = softc; 1674219888Sed vd->vd_driver->vd_init(vd); 1675256145Sray 1676219888Sed vt_upgrade(vd); 1677256145Sray 1678256145Sray /* Refill settings with new sizes. */ 1679256145Sray vt_resize(vd); 1680256145Sray 1681256145Sray if (vd->vd_flags & VDF_SPLASH) 1682256145Sray vtterm_splash(vd); 1683256145Sray 1684256145Sray if (vd->vd_curwindow != NULL) 1685256145Sray callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 1686256145Sray 1687256145Sray termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 1688256903Sray 1689256903Sray /* Update console window sizes to actual. */ 1690256903Sray vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz); 1691256903Sray terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz); 1692219888Sed} 1693257815Sray 1694257815Srayvoid 1695257815Srayvt_suspend() 1696257815Sray{ 1697257815Sray 1698258023Sray if (vt_suspendswitch == 0) 1699258023Sray return; 1700257815Sray /* Save current window. */ 1701257815Sray main_vd->vd_savedwindow = main_vd->vd_curwindow; 1702257815Sray /* Ask holding process to free window and switch to console window */ 1703257815Sray vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]); 1704257815Sray} 1705257815Sray 1706257815Srayvoid 1707257815Srayvt_resume() 1708257815Sray{ 1709257815Sray 1710258023Sray if (vt_suspendswitch == 0) 1711258023Sray return; 1712257815Sray /* Switch back to saved window */ 1713257815Sray if (main_vd->vd_savedwindow != NULL) 1714257815Sray vt_proc_window_switch(main_vd->vd_savedwindow); 1715257815Sray main_vd->vd_savedwindow = NULL; 1716257815Sray} 1717