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$"); 35219888Sed 36263817Sray#include "opt_compat.h" 37263817Sray 38219888Sed#include <sys/param.h> 39219888Sed#include <sys/consio.h> 40219888Sed#include <sys/eventhandler.h> 41219888Sed#include <sys/fbio.h> 42219888Sed#include <sys/kbio.h> 43219888Sed#include <sys/kdb.h> 44219888Sed#include <sys/kernel.h> 45219888Sed#include <sys/lock.h> 46219888Sed#include <sys/malloc.h> 47219888Sed#include <sys/mutex.h> 48258947Sray#include <sys/priv.h> 49256145Sray#include <sys/proc.h> 50219888Sed#include <sys/reboot.h> 51219888Sed#include <sys/systm.h> 52219888Sed#include <sys/terminal.h> 53219888Sed 54219888Sed#include <dev/kbd/kbdreg.h> 55219888Sed#include <dev/vt/vt.h> 56219888Sed 57258947Sray#if defined(__i386__) || defined(__amd64__) 58258947Sray#include <machine/psl.h> 59258947Sray#include <machine/frame.h> 60258947Sray#endif 61258947Sray 62219888Sedstatic tc_bell_t vtterm_bell; 63219888Sedstatic tc_cursor_t vtterm_cursor; 64219888Sedstatic tc_putchar_t vtterm_putchar; 65219888Sedstatic tc_fill_t vtterm_fill; 66219888Sedstatic tc_copy_t vtterm_copy; 67219888Sedstatic tc_param_t vtterm_param; 68219888Sedstatic tc_done_t vtterm_done; 69219888Sed 70219888Sedstatic tc_cnprobe_t vtterm_cnprobe; 71219888Sedstatic tc_cngetc_t vtterm_cngetc; 72219888Sed 73219888Sedstatic tc_opened_t vtterm_opened; 74219888Sedstatic tc_ioctl_t vtterm_ioctl; 75263817Sraystatic tc_mmap_t vtterm_mmap; 76219888Sed 77219888Sedconst struct terminal_class vt_termclass = { 78219888Sed .tc_bell = vtterm_bell, 79219888Sed .tc_cursor = vtterm_cursor, 80219888Sed .tc_putchar = vtterm_putchar, 81219888Sed .tc_fill = vtterm_fill, 82219888Sed .tc_copy = vtterm_copy, 83219888Sed .tc_param = vtterm_param, 84219888Sed .tc_done = vtterm_done, 85219888Sed 86219888Sed .tc_cnprobe = vtterm_cnprobe, 87219888Sed .tc_cngetc = vtterm_cngetc, 88219888Sed 89219888Sed .tc_opened = vtterm_opened, 90219888Sed .tc_ioctl = vtterm_ioctl, 91263817Sray .tc_mmap = vtterm_mmap, 92219888Sed}; 93219888Sed 94219888Sed/* 95257296Snwhitehorn * Use a constant timer of 25 Hz to redraw the screen. 96219888Sed * 97219888Sed * XXX: In theory we should only fire up the timer when there is really 98219888Sed * activity. Unfortunately we cannot always start timers. We really 99219888Sed * don't want to process kernel messages synchronously, because it 100219888Sed * really slows down the system. 101219888Sed */ 102257296Snwhitehorn#define VT_TIMERFREQ 25 103219888Sed 104219888Sed/* Bell pitch/duration. */ 105219888Sed#define VT_BELLDURATION ((5 * hz + 99) / 100) 106219888Sed#define VT_BELLPITCH 800 107219888Sed 108219888Sed#define VT_LOCK(vd) mtx_lock(&(vd)->vd_lock) 109219888Sed#define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) 110219888Sed 111219888Sed#define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \ 112219888Sed (vw)->vw_number) 113219888Sed 114256145Sray/* XXX while syscons is here. */ 115256145Srayint sc_txtmouse_no_retrace_wait; 116256145Sray 117263817Sraystatic SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "vt(9) parameters"); 118263817SrayVT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)"); 119263817SrayVT_SYSCTL_INT(debug, 0, "vt(9) debug level"); 120256145SrayVT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode"); 121258023SrayVT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend"); 122256145Sray 123219888Sedstatic unsigned int vt_unit = 0; 124219888Sedstatic MALLOC_DEFINE(M_VT, "vt", "vt device"); 125256145Sraystruct vt_device *main_vd = NULL; 126219888Sed 127219888Sed/* Boot logo. */ 128219888Sedextern unsigned int vt_logo_width; 129219888Sedextern unsigned int vt_logo_height; 130219888Sedextern unsigned int vt_logo_depth; 131219888Sedextern unsigned char vt_logo_image[]; 132219888Sed 133219888Sed/* Font. */ 134219888Sedextern struct vt_font vt_font_default; 135263817Sray#ifndef SC_NO_CUTPASTE 136257986Srayextern struct mouse_cursor vt_default_mouse_pointer; 137263817Sray#endif 138219888Sed 139256145Sraystatic int signal_vt_rel(struct vt_window *); 140256145Sraystatic int signal_vt_acq(struct vt_window *); 141256145Sraystatic int finish_vt_rel(struct vt_window *, int, int *); 142256145Sraystatic int finish_vt_acq(struct vt_window *); 143256145Sraystatic int vt_window_switch(struct vt_window *); 144256145Sraystatic int vt_late_window_switch(struct vt_window *); 145256145Sraystatic int vt_proc_alive(struct vt_window *); 146256145Sraystatic void vt_resize(struct vt_device *); 147256145Sray 148219888Sedstatic void 149256145Srayvt_switch_timer(void *arg) 150256145Sray{ 151256145Sray 152256145Sray vt_late_window_switch((struct vt_window *)arg); 153256145Sray} 154256145Sray 155256145Sraystatic int 156256145Srayvt_window_preswitch(struct vt_window *vw, struct vt_window *curvw) 157256145Sray{ 158256145Sray 159256145Sray DPRINTF(40, "%s\n", __func__); 160256145Sray curvw->vw_switch_to = vw; 161256145Sray /* Set timer to allow switch in case when process hang. */ 162256145Sray callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer, 163256145Sray vt_switch_timer, (void *)vw); 164256145Sray /* Notify process about vt switch attempt. */ 165256145Sray DPRINTF(30, "%s: Notify process.\n", __func__); 166256145Sray signal_vt_rel(curvw); 167256145Sray 168256145Sray return (0); 169256145Sray} 170256145Sray 171256145Sraystatic int 172256145Srayvt_window_postswitch(struct vt_window *vw) 173256145Sray{ 174256145Sray 175256145Sray signal_vt_acq(vw); 176256145Sray return (0); 177256145Sray} 178256145Sray 179256145Sray/* vt_late_window_switch will done VT switching for regular case. */ 180256145Sraystatic int 181256145Srayvt_late_window_switch(struct vt_window *vw) 182256145Sray{ 183256145Sray int ret; 184256145Sray 185256145Sray callout_stop(&vw->vw_proc_dead_timer); 186256145Sray 187256145Sray ret = vt_window_switch(vw); 188256145Sray if (ret) 189256145Sray return (ret); 190256145Sray 191256145Sray /* Notify owner process about terminal availability. */ 192256145Sray if (vw->vw_smode.mode == VT_PROCESS) { 193256145Sray ret = vt_window_postswitch(vw); 194256145Sray } 195256145Sray return (ret); 196256145Sray} 197256145Sray 198256145Sray/* Switch window. */ 199256145Sraystatic int 200256145Srayvt_proc_window_switch(struct vt_window *vw) 201256145Sray{ 202256145Sray struct vt_window *curvw; 203256145Sray struct vt_device *vd; 204256145Sray int ret; 205256145Sray 206256145Sray if (vw->vw_flags & VWF_VTYLOCK) 207256145Sray return (EBUSY); 208256145Sray 209256145Sray vd = vw->vw_device; 210256145Sray curvw = vd->vd_curwindow; 211256145Sray 212256145Sray /* Ask current process permitions to switch away. */ 213256145Sray if (curvw->vw_smode.mode == VT_PROCESS) { 214256145Sray DPRINTF(30, "%s: VT_PROCESS ", __func__); 215256145Sray if (vt_proc_alive(curvw) == FALSE) { 216256145Sray DPRINTF(30, "Dead. Cleaning."); 217256145Sray /* Dead */ 218256145Sray } else { 219256145Sray DPRINTF(30, "%s: Signaling process.\n", __func__); 220256145Sray /* Alive, try to ask him. */ 221256145Sray ret = vt_window_preswitch(vw, curvw); 222256145Sray /* Wait for process answer or timeout. */ 223256145Sray return (ret); 224256145Sray } 225256145Sray DPRINTF(30, "\n"); 226256145Sray } 227256145Sray 228256145Sray ret = vt_late_window_switch(vw); 229256145Sray return (ret); 230256145Sray} 231256145Sray 232256145Sray/* Switch window ignoring process locking. */ 233256145Sraystatic int 234219888Sedvt_window_switch(struct vt_window *vw) 235219888Sed{ 236219888Sed struct vt_device *vd = vw->vw_device; 237256145Sray struct vt_window *curvw = vd->vd_curwindow; 238219888Sed keyboard_t *kbd; 239219888Sed 240219888Sed VT_LOCK(vd); 241256145Sray if (curvw == vw) { 242256145Sray /* Nothing to do. */ 243219888Sed VT_UNLOCK(vd); 244256145Sray return (0); 245219888Sed } 246256145Sray if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) { 247256145Sray VT_UNLOCK(vd); 248256145Sray return (EINVAL); 249256145Sray } 250256145Sray 251219888Sed vd->vd_curwindow = vw; 252219888Sed vd->vd_flags |= VDF_INVALID; 253219888Sed cv_broadcast(&vd->vd_winswitch); 254219888Sed VT_UNLOCK(vd); 255219888Sed 256256145Sray if (vd->vd_driver->vd_postswitch) 257256145Sray vd->vd_driver->vd_postswitch(vd); 258256145Sray 259219888Sed /* Restore per-window keyboard mode. */ 260219888Sed mtx_lock(&Giant); 261219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 262256145Sray if (kbd != NULL) { 263219888Sed kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode); 264256145Sray } 265219888Sed mtx_unlock(&Giant); 266256145Sray DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number); 267256145Sray 268256145Sray return (0); 269219888Sed} 270219888Sed 271219888Sedstatic inline void 272219888Sedvt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size) 273219888Sed{ 274219888Sed 275219888Sed size->tp_row = vd->vd_height; 276219888Sed size->tp_col = vd->vd_width; 277219888Sed if (vf != NULL) { 278219888Sed size->tp_row /= vf->vf_height; 279219888Sed size->tp_col /= vf->vf_width; 280219888Sed } 281219888Sed} 282219888Sed 283219888Sedstatic inline void 284219888Sedvt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size) 285219888Sed{ 286219888Sed 287219888Sed size->ws_row = size->ws_ypixel = vd->vd_height; 288219888Sed size->ws_col = size->ws_xpixel = vd->vd_width; 289219888Sed if (vf != NULL) { 290219888Sed size->ws_row /= vf->vf_height; 291219888Sed size->ws_col /= vf->vf_width; 292219888Sed } 293219888Sed} 294219888Sed 295257076Sraystatic void 296257076Srayvt_scroll(struct vt_window *vw, int offset, int whence) 297257076Sray{ 298257076Sray int diff; 299257076Sray term_pos_t size; 300257076Sray 301257076Sray if ((vw->vw_flags & VWF_SCROLL) == 0) 302257076Sray return; 303257076Sray 304257076Sray vt_termsize(vw->vw_device, vw->vw_font, &size); 305257076Sray 306257076Sray diff = vthistory_seek(&vw->vw_buf, offset, whence); 307257076Sray /* 308257076Sray * Offset changed, please update Nth lines on sceen. 309257076Sray * +N - Nth lines at top; 310257076Sray * -N - Nth lines at bottom. 311257076Sray */ 312257076Sray 313257076Sray if (diff < -size.tp_row || diff > size.tp_row) { 314257076Sray vw->vw_device->vd_flags |= VDF_INVALID; 315257076Sray return; 316257076Sray } 317257076Sray vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/ 318257076Sray} 319257076Sray 320219888Sedstatic int 321257076Srayvt_machine_kbdevent(int c) 322257076Sray{ 323257076Sray 324257076Sray switch (c) { 325257076Sray case SPCLKEY | DBG: 326257076Sray kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); 327257076Sray return (1); 328257076Sray case SPCLKEY | RBT: 329257076Sray /* XXX: Make this configurable! */ 330257076Sray shutdown_nice(0); 331257076Sray return (1); 332257076Sray case SPCLKEY | HALT: 333257076Sray shutdown_nice(RB_HALT); 334257076Sray return (1); 335257076Sray case SPCLKEY | PDWN: 336257076Sray shutdown_nice(RB_HALT|RB_POWEROFF); 337257076Sray return (1); 338257076Sray }; 339257076Sray 340257076Sray return (0); 341257076Sray} 342257076Sray 343257076Sraystatic void 344257076Srayvt_scrollmode_kbdevent(struct vt_window *vw, int c, int console) 345257076Sray{ 346257076Sray struct vt_device *vd; 347257076Sray term_pos_t size; 348257076Sray 349257076Sray vd = vw->vw_device; 350257076Sray /* Only special keys handled in ScrollLock mode */ 351257076Sray if ((c & SPCLKEY) == 0) 352257076Sray return; 353257076Sray 354257076Sray c &= ~SPCLKEY; 355257076Sray 356257076Sray if (console == 0) { 357257076Sray if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 358257076Sray vw = vd->vd_windows[c - F_SCR]; 359257076Sray if (vw != NULL) 360257076Sray vt_proc_window_switch(vw); 361257076Sray return; 362257076Sray } 363257076Sray VT_LOCK(vd); 364257076Sray } 365257076Sray 366257076Sray switch (c) { 367257076Sray case SLK: { 368257076Sray /* Turn scrolling off. */ 369257076Sray vt_scroll(vw, 0, VHS_END); 370257076Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 371258408Sray vw->vw_flags &= ~VWF_SCROLL; 372257076Sray break; 373257076Sray } 374257076Sray case FKEY | F(49): /* Home key. */ 375258506Sray vt_scroll(vw, 0, VHS_SET); 376257076Sray break; 377257076Sray case FKEY | F(50): /* Arrow up. */ 378257076Sray vt_scroll(vw, -1, VHS_CUR); 379257076Sray break; 380257076Sray case FKEY | F(51): /* Page up. */ 381257076Sray vt_termsize(vd, vw->vw_font, &size); 382257076Sray vt_scroll(vw, -size.tp_row, VHS_CUR); 383257076Sray break; 384257076Sray case FKEY | F(57): /* End key. */ 385258506Sray vt_scroll(vw, 0, VHS_END); 386257076Sray break; 387257076Sray case FKEY | F(58): /* Arrow down. */ 388257076Sray vt_scroll(vw, 1, VHS_CUR); 389257076Sray break; 390257076Sray case FKEY | F(59): /* Page down. */ 391257076Sray vt_termsize(vd, vw->vw_font, &size); 392257076Sray vt_scroll(vw, size.tp_row, VHS_CUR); 393257076Sray break; 394257076Sray } 395257076Sray 396257076Sray if (console == 0) 397257076Sray VT_UNLOCK(vd); 398257076Sray} 399257076Sray 400257076Sraystatic int 401257294Snwhitehornvt_processkey(keyboard_t *kbd, struct vt_device *vd, int c) 402219888Sed{ 403219888Sed struct vt_window *vw = vd->vd_curwindow; 404257294Snwhitehorn int state = 0; 405219888Sed 406258165Sray#if VT_ALT_TO_ESC_HACK 407258165Sray if (c & RELKEY) { 408258165Sray switch (c & ~RELKEY) { 409258165Sray case (SPCLKEY | RALT): 410263817Sray if (vt_enable_altgr != 0) 411263817Sray break; 412258165Sray case (SPCLKEY | LALT): 413258165Sray vd->vd_kbstate &= ~ALKED; 414258165Sray } 415258165Sray /* Other keys ignored for RELKEY event. */ 416258165Sray return (0); 417258165Sray } else { 418258165Sray switch (c & ~RELKEY) { 419258165Sray case (SPCLKEY | RALT): 420263817Sray if (vt_enable_altgr != 0) 421263817Sray break; 422258165Sray case (SPCLKEY | LALT): 423258165Sray vd->vd_kbstate |= ALKED; 424258165Sray } 425258165Sray } 426258165Sray#else 427219888Sed if (c & RELKEY) 428258165Sray /* Other keys ignored for RELKEY event. */ 429219888Sed return (0); 430258165Sray#endif 431219888Sed 432257076Sray if (vt_machine_kbdevent(c)) 433257076Sray return (0); 434257076Sray 435257076Sray if (vw->vw_flags & VWF_SCROLL) { 436257076Sray vt_scrollmode_kbdevent(vw, c, 0/* Not a console */); 437257076Sray /* Scroll mode keys handled, nothing to do more. */ 438257076Sray return (0); 439257076Sray } 440257076Sray 441219888Sed if (c & SPCLKEY) { 442219888Sed c &= ~SPCLKEY; 443219888Sed 444219888Sed if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) { 445219888Sed vw = vd->vd_windows[c - F_SCR]; 446219888Sed if (vw != NULL) 447256145Sray vt_proc_window_switch(vw); 448219888Sed return (0); 449219888Sed } 450219888Sed 451219888Sed switch (c) { 452219888Sed case SLK: { 453219888Sed 454219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 455219888Sed VT_LOCK(vd); 456219888Sed if (state & SLKED) { 457219888Sed /* Turn scrolling on. */ 458258408Sray vw->vw_flags |= VWF_SCROLL; 459256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 460219888Sed } else { 461219888Sed /* Turn scrolling off. */ 462258408Sray vw->vw_flags &= ~VWF_SCROLL; 463256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 464257076Sray vt_scroll(vw, 0, VHS_END); 465219888Sed } 466219888Sed VT_UNLOCK(vd); 467219888Sed break; 468219888Sed } 469219888Sed case FKEY | F(1): case FKEY | F(2): case FKEY | F(3): 470219888Sed case FKEY | F(4): case FKEY | F(5): case FKEY | F(6): 471219888Sed case FKEY | F(7): case FKEY | F(8): case FKEY | F(9): 472219888Sed case FKEY | F(10): case FKEY | F(11): case FKEY | F(12): 473219888Sed /* F1 through F12 keys. */ 474219888Sed terminal_input_special(vw->vw_terminal, 475219888Sed TKEY_F1 + c - (FKEY | F(1))); 476219888Sed break; 477219888Sed case FKEY | F(49): /* Home key. */ 478219888Sed terminal_input_special(vw->vw_terminal, TKEY_HOME); 479219888Sed break; 480219888Sed case FKEY | F(50): /* Arrow up. */ 481219888Sed terminal_input_special(vw->vw_terminal, TKEY_UP); 482219888Sed break; 483219888Sed case FKEY | F(51): /* Page up. */ 484219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP); 485219888Sed break; 486219888Sed case FKEY | F(53): /* Arrow left. */ 487219888Sed terminal_input_special(vw->vw_terminal, TKEY_LEFT); 488219888Sed break; 489219888Sed case FKEY | F(55): /* Arrow right. */ 490219888Sed terminal_input_special(vw->vw_terminal, TKEY_RIGHT); 491219888Sed break; 492219888Sed case FKEY | F(57): /* End key. */ 493219888Sed terminal_input_special(vw->vw_terminal, TKEY_END); 494219888Sed break; 495219888Sed case FKEY | F(58): /* Arrow down. */ 496219888Sed terminal_input_special(vw->vw_terminal, TKEY_DOWN); 497219888Sed break; 498219888Sed case FKEY | F(59): /* Page down. */ 499219888Sed terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN); 500219888Sed break; 501219888Sed case FKEY | F(60): /* Insert key. */ 502219888Sed terminal_input_special(vw->vw_terminal, TKEY_INSERT); 503219888Sed break; 504219888Sed case FKEY | F(61): /* Delete key. */ 505219888Sed terminal_input_special(vw->vw_terminal, TKEY_DELETE); 506219888Sed break; 507219888Sed } 508219888Sed } else if (KEYFLAGS(c) == 0) { 509219888Sed /* Don't do UTF-8 conversion when doing raw mode. */ 510258165Sray if (vw->vw_kbdmode == K_XLATE) { 511258165Sray#if VT_ALT_TO_ESC_HACK 512258165Sray if (vd->vd_kbstate & ALKED) { 513258165Sray /* 514258165Sray * Prepend ESC sequence if one of ALT keys down. 515258165Sray */ 516258165Sray terminal_input_char(vw->vw_terminal, 0x1b); 517258165Sray } 518258165Sray#endif 519258165Sray 520256145Sray terminal_input_char(vw->vw_terminal, KEYCHAR(c)); 521258165Sray } else 522219888Sed terminal_input_raw(vw->vw_terminal, c); 523219888Sed } 524219888Sed return (0); 525219888Sed} 526219888Sed 527219888Sedstatic int 528257294Snwhitehornvt_kbdevent(keyboard_t *kbd, int event, void *arg) 529257294Snwhitehorn{ 530257294Snwhitehorn struct vt_device *vd = arg; 531257294Snwhitehorn int c; 532257294Snwhitehorn 533257294Snwhitehorn switch (event) { 534257294Snwhitehorn case KBDIO_KEYINPUT: 535257294Snwhitehorn break; 536257294Snwhitehorn case KBDIO_UNLOADING: 537257294Snwhitehorn mtx_lock(&Giant); 538257294Snwhitehorn vd->vd_keyboard = -1; 539257294Snwhitehorn kbd_release(kbd, (void *)&vd->vd_keyboard); 540257294Snwhitehorn mtx_unlock(&Giant); 541257294Snwhitehorn return (0); 542257294Snwhitehorn default: 543257294Snwhitehorn return (EINVAL); 544257294Snwhitehorn } 545257294Snwhitehorn 546257294Snwhitehorn while ((c = kbdd_read_char(kbd, 0)) != NOKEY) 547257294Snwhitehorn vt_processkey(kbd, vd, c); 548257294Snwhitehorn 549257294Snwhitehorn return (0); 550257294Snwhitehorn} 551257294Snwhitehorn 552257294Snwhitehornstatic int 553219888Sedvt_allocate_keyboard(struct vt_device *vd) 554219888Sed{ 555219888Sed int idx0, idx; 556219888Sed keyboard_t *k0, *k; 557219888Sed keyboard_info_t ki; 558219888Sed 559219888Sed idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard, 560219888Sed vt_kbdevent, vd); 561256145Sray /* XXX: kb_token lost */ 562256145Sray vd->vd_keyboard = idx0; 563219888Sed if (idx0 != -1) { 564256145Sray DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0); 565219888Sed k0 = kbd_get_keyboard(idx0); 566219888Sed 567219888Sed for (idx = kbd_find_keyboard2("*", -1, 0); 568219888Sed idx != -1; 569219888Sed idx = kbd_find_keyboard2("*", -1, idx + 1)) { 570219888Sed k = kbd_get_keyboard(idx); 571219888Sed 572219888Sed if (idx == idx0 || KBD_IS_BUSY(k)) 573219888Sed continue; 574219888Sed 575219888Sed bzero(&ki, sizeof(ki)); 576219888Sed strcpy(ki.kb_name, k->kb_name); 577219888Sed ki.kb_unit = k->kb_unit; 578219888Sed 579219888Sed kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); 580219888Sed } 581256145Sray } else { 582256145Sray DPRINTF(20, "%s: no kbdmux allocated\n", __func__); 583219888Sed idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard, 584219888Sed vt_kbdevent, vd); 585256145Sray } 586256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 587219888Sed 588219888Sed return (idx0); 589219888Sed} 590219888Sed 591219888Sedstatic void 592219888Sedvtterm_bell(struct terminal *tm) 593219888Sed{ 594263817Sray struct vt_window *vw = tm->tm_softc; 595263817Sray struct vt_device *vd = vw->vw_device; 596219888Sed 597263817Sray if (vd->vd_flags & VDF_QUIET_BELL) 598263817Sray return; 599263817Sray 600219888Sed sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION); 601219888Sed} 602219888Sed 603219888Sedstatic void 604219888Sedvtterm_cursor(struct terminal *tm, const term_pos_t *p) 605219888Sed{ 606219888Sed struct vt_window *vw = tm->tm_softc; 607219888Sed 608219888Sed vtbuf_cursor_position(&vw->vw_buf, p); 609219888Sed} 610219888Sed 611219888Sedstatic void 612219888Sedvtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c) 613219888Sed{ 614219888Sed struct vt_window *vw = tm->tm_softc; 615219888Sed 616219888Sed vtbuf_putchar(&vw->vw_buf, p, c); 617219888Sed} 618219888Sed 619219888Sedstatic void 620219888Sedvtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c) 621219888Sed{ 622219888Sed struct vt_window *vw = tm->tm_softc; 623219888Sed 624256145Sray vtbuf_fill_locked(&vw->vw_buf, r, c); 625219888Sed} 626219888Sed 627219888Sedstatic void 628219888Sedvtterm_copy(struct terminal *tm, const term_rect_t *r, 629219888Sed const term_pos_t *p) 630219888Sed{ 631219888Sed struct vt_window *vw = tm->tm_softc; 632219888Sed 633219888Sed vtbuf_copy(&vw->vw_buf, r, p); 634219888Sed} 635219888Sed 636219888Sedstatic void 637219888Sedvtterm_param(struct terminal *tm, int cmd, unsigned int arg) 638219888Sed{ 639219888Sed struct vt_window *vw = tm->tm_softc; 640219888Sed 641219888Sed switch (cmd) { 642219888Sed case TP_SHOWCURSOR: 643219888Sed vtbuf_cursor_visibility(&vw->vw_buf, arg); 644219888Sed break; 645263817Sray case TP_MOUSE: 646263817Sray vw->vw_mouse_level = arg; 647263817Sray break; 648219888Sed } 649219888Sed} 650219888Sed 651219888Sedstatic inline void 652219888Sedvt_determine_colors(term_char_t c, int cursor, 653219888Sed term_color_t *fg, term_color_t *bg) 654219888Sed{ 655264612Sray term_color_t tmp; 656264612Sray int invert; 657219888Sed 658264612Sray invert = 0; 659264612Sray 660219888Sed *fg = TCHAR_FGCOLOR(c); 661219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) 662219888Sed *fg = TCOLOR_LIGHT(*fg); 663219888Sed *bg = TCHAR_BGCOLOR(c); 664219888Sed 665264612Sray if (TCHAR_FORMAT(c) & TF_REVERSE) 666264612Sray invert ^= 1; 667264612Sray if (cursor) 668264612Sray invert ^= 1; 669219888Sed 670264612Sray if (invert) { 671219888Sed tmp = *fg; 672219888Sed *fg = *bg; 673219888Sed *bg = tmp; 674219888Sed } 675219888Sed} 676219888Sed 677219888Sedstatic void 678219888Sedvt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c, 679219888Sed int iscursor, unsigned int row, unsigned int col) 680219888Sed{ 681219888Sed term_color_t fg, bg; 682219888Sed 683219888Sed vt_determine_colors(c, iscursor, &fg, &bg); 684219888Sed 685219888Sed if (vf != NULL) { 686219888Sed const uint8_t *src; 687219888Sed vt_axis_t top, left; 688219888Sed 689219888Sed src = vtfont_lookup(vf, c); 690219888Sed 691219888Sed /* 692219888Sed * Align the terminal to the centre of the screen. 693219888Sed * Fonts may not always be able to fill the entire 694219888Sed * screen. 695219888Sed */ 696257979Sray top = row * vf->vf_height + vd->vd_offset.tp_row; 697257979Sray left = col * vf->vf_width + vd->vd_offset.tp_col; 698219888Sed 699257988Sray vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left, 700219888Sed vf->vf_width, vf->vf_height, fg, bg); 701219888Sed } else { 702219888Sed vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c), 703219888Sed row, col, fg, bg); 704219888Sed } 705219888Sed} 706219888Sed 707219888Sedstatic void 708219888Sedvt_flush(struct vt_device *vd) 709219888Sed{ 710264456Sray struct vt_window *vw; 711264456Sray struct vt_font *vf; 712219888Sed struct vt_bufmask tmask; 713256145Sray unsigned int row, col; 714257981Sray term_rect_t tarea; 715257981Sray term_pos_t size; 716256145Sray term_char_t *r; 717263817Sray#ifndef SC_NO_CUTPASTE 718263817Sray struct mouse_cursor *m; 719257988Sray int bpl, h, w; 720263817Sray#endif 721219888Sed 722264456Sray vw = vd->vd_curwindow; 723264456Sray if (vw == NULL) 724264456Sray return; 725264456Sray vf = vw->vw_font; 726264456Sray if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL)) 727264456Sray return; 728264456Sray 729219888Sed if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY) 730219888Sed return; 731219888Sed 732219888Sed vtbuf_undirty(&vw->vw_buf, &tarea, &tmask); 733219888Sed vt_termsize(vd, vf, &size); 734219888Sed 735219888Sed /* Force a full redraw when the screen contents are invalid. */ 736256145Sray if (vd->vd_flags & VDF_INVALID) { 737219888Sed tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0; 738219888Sed tarea.tr_end = size; 739219888Sed tmask.vbm_row = tmask.vbm_col = VBM_DIRTY; 740219888Sed 741219888Sed vd->vd_flags &= ~VDF_INVALID; 742219888Sed } 743219888Sed 744263817Sray#ifndef SC_NO_CUTPASTE 745258327Sray if ((vw->vw_flags & VWF_MOUSE_HIDE) == 0) { 746258327Sray /* Mark last mouse position as dirty to erase. */ 747258327Sray vtbuf_mouse_cursor_position(&vw->vw_buf, vd->vd_mdirtyx, 748258327Sray vd->vd_mdirtyy); 749258327Sray } 750263817Sray#endif 751257981Sray 752219888Sed for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) { 753219888Sed if (!VTBUF_DIRTYROW(&tmask, row)) 754219888Sed continue; 755256145Sray r = VTBUF_GET_ROW(&vw->vw_buf, row); 756219888Sed for (col = tarea.tr_begin.tp_col; 757219888Sed col < tarea.tr_end.tp_col; col++) { 758219888Sed if (!VTBUF_DIRTYCOL(&tmask, col)) 759219888Sed continue; 760219888Sed 761256145Sray vt_bitblt_char(vd, vf, r[col], 762256903Sray VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col); 763219888Sed } 764219888Sed } 765257981Sray 766263817Sray#ifndef SC_NO_CUTPASTE 767258327Sray /* Mouse disabled. */ 768258327Sray if (vw->vw_flags & VWF_MOUSE_HIDE) 769258327Sray return; 770258327Sray 771258110Sray /* No mouse for DDB. */ 772258110Sray if (kdb_active || panicstr != NULL) 773258110Sray return; 774258110Sray 775257981Sray if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) == 776257981Sray VDF_MOUSECURSOR) { 777257981Sray m = &vt_default_mouse_pointer; 778257988Sray bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */ 779257981Sray w = m->w; 780257981Sray h = m->h; 781257981Sray 782257981Sray if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width)) 783257981Sray w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1; 784257981Sray if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height)) 785257981Sray h = (size.tp_row * vf->vf_height) - vd->vd_my - 1; 786257981Sray 787264113Sray vd->vd_driver->vd_maskbitbltchr(vd, m->map, m->mask, bpl, 788257981Sray vd->vd_offset.tp_row + vd->vd_my, 789257981Sray vd->vd_offset.tp_col + vd->vd_mx, 790257981Sray w, h, TC_WHITE, TC_BLACK); 791257981Sray /* Save point of last mouse cursor to erase it later. */ 792257981Sray vd->vd_mdirtyx = vd->vd_mx / vf->vf_width; 793257981Sray vd->vd_mdirtyy = vd->vd_my / vf->vf_height; 794257981Sray } 795263817Sray#endif 796219888Sed} 797219888Sed 798219888Sedstatic void 799219888Sedvt_timer(void *arg) 800219888Sed{ 801257387Sray struct vt_device *vd; 802219888Sed 803257387Sray vd = arg; 804257387Sray /* Update screen if required. */ 805219888Sed vt_flush(vd); 806264456Sray 807257387Sray /* Schedule for next update. */ 808219888Sed callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 809219888Sed} 810219888Sed 811219888Sedstatic void 812219888Sedvtterm_done(struct terminal *tm) 813219888Sed{ 814219888Sed struct vt_window *vw = tm->tm_softc; 815219888Sed struct vt_device *vd = vw->vw_device; 816219888Sed 817219888Sed if (kdb_active || panicstr != NULL) { 818219888Sed /* Switch to the debugger. */ 819219888Sed if (vd->vd_curwindow != vw) { 820219888Sed vd->vd_curwindow = vw; 821219888Sed vd->vd_flags |= VDF_INVALID; 822257626Sray if (vd->vd_driver->vd_postswitch) 823257626Sray vd->vd_driver->vd_postswitch(vd); 824219888Sed } 825219888Sed vd->vd_flags &= ~VDF_SPLASH; 826219888Sed vt_flush(vd); 827219888Sed } else if (!(vd->vd_flags & VDF_ASYNC)) { 828219888Sed vt_flush(vd); 829219888Sed } 830219888Sed} 831219888Sed 832263817Sray#ifdef DEV_SPLASH 833219888Sedstatic void 834256145Srayvtterm_splash(struct vt_device *vd) 835256145Sray{ 836256145Sray vt_axis_t top, left; 837256145Sray 838256145Sray /* Display a nice boot splash. */ 839257722Sray if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) { 840256145Sray 841256145Sray top = (vd->vd_height - vt_logo_height) / 2; 842256145Sray left = (vd->vd_width - vt_logo_width) / 2; 843256145Sray switch (vt_logo_depth) { 844256145Sray case 1: 845256145Sray /* XXX: Unhardcode colors! */ 846257988Sray vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0, 847257988Sray top, left, vt_logo_width, vt_logo_height, 0xf, 0x0); 848256145Sray } 849256145Sray vd->vd_flags |= VDF_SPLASH; 850256145Sray } 851256145Sray} 852263817Sray#endif 853256145Sray 854256145Sraystatic void 855219888Sedvtterm_cnprobe(struct terminal *tm, struct consdev *cp) 856219888Sed{ 857219888Sed struct vt_window *vw = tm->tm_softc; 858219888Sed struct vt_device *vd = vw->vw_device; 859219888Sed struct winsize wsz; 860219888Sed 861256145Sray if (vd->vd_flags & VDF_INITIALIZED) 862256145Sray /* Initialization already done. */ 863256145Sray return; 864256145Sray 865219888Sed cp->cn_pri = vd->vd_driver->vd_init(vd); 866219888Sed if (cp->cn_pri == CN_DEAD) { 867219888Sed vd->vd_flags |= VDF_DEAD; 868219888Sed return; 869219888Sed } 870219888Sed 871230469Snwhitehorn /* Initialize any early-boot keyboard drivers */ 872230469Snwhitehorn kbd_configure(KB_CONF_PROBE_ONLY); 873230469Snwhitehorn 874219888Sed vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1); 875256145Sray vd->vd_windows[VT_CONSWINDOW] = vw; 876219888Sed sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); 877219888Sed 878219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 879219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 880219888Sed 881219888Sed vtbuf_init_early(&vw->vw_buf); 882219888Sed vt_winsize(vd, vw->vw_font, &wsz); 883219888Sed terminal_set_winsize(tm, &wsz); 884219888Sed 885263817Sray#ifdef DEV_SPLASH 886256145Sray vtterm_splash(vd); 887263817Sray#endif 888219888Sed 889256145Sray vd->vd_flags |= VDF_INITIALIZED; 890256145Sray main_vd = vd; 891219888Sed} 892219888Sed 893219888Sedstatic int 894219888Sedvtterm_cngetc(struct terminal *tm) 895219888Sed{ 896219888Sed struct vt_window *vw = tm->tm_softc; 897219888Sed struct vt_device *vd = vw->vw_device; 898219888Sed keyboard_t *kbd; 899257076Sray int state; 900219888Sed u_int c; 901219888Sed 902257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 903257076Sray return (*vw->vw_kbdsq++); 904257076Sray 905257076Sray state = 0; 906219888Sed /* Make sure the splash screen is not there. */ 907219888Sed if (vd->vd_flags & VDF_SPLASH) { 908256145Sray /* Remove splash */ 909219888Sed vd->vd_flags &= ~VDF_SPLASH; 910256145Sray /* Mark screen as invalid to force update */ 911256145Sray vd->vd_flags |= VDF_INVALID; 912219888Sed vt_flush(vd); 913219888Sed } 914219888Sed 915219888Sed /* Stripped down keyboard handler. */ 916219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 917219888Sed if (kbd == NULL) 918219888Sed return (-1); 919219888Sed 920256145Sray /* Force keyboard input mode to K_XLATE */ 921256145Sray c = K_XLATE; 922256145Sray kbdd_ioctl(kbd, KDSKBMODE, (void *)&c); 923256145Sray 924219888Sed /* Switch the keyboard to polling to make it work here. */ 925219888Sed kbdd_poll(kbd, TRUE); 926219888Sed c = kbdd_read_char(kbd, 0); 927219888Sed kbdd_poll(kbd, FALSE); 928219888Sed if (c & RELKEY) 929219888Sed return (-1); 930256145Sray 931257076Sray if (vw->vw_flags & VWF_SCROLL) { 932257076Sray vt_scrollmode_kbdevent(vw, c, 1/* Console mode */); 933257076Sray vt_flush(vd); 934257076Sray return (-1); 935257076Sray } 936257076Sray 937219888Sed /* Stripped down handling of vt_kbdevent(), without locking, etc. */ 938219888Sed if (c & SPCLKEY) { 939219888Sed switch (c) { 940257076Sray case SPCLKEY | SLK: 941219888Sed kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state); 942219888Sed if (state & SLKED) { 943219888Sed /* Turn scrolling on. */ 944258408Sray vw->vw_flags |= VWF_SCROLL; 945256145Sray VTBUF_SLCK_ENABLE(&vw->vw_buf); 946219888Sed } else { 947219888Sed /* Turn scrolling off. */ 948257076Sray vt_scroll(vw, 0, VHS_END); 949258408Sray vw->vw_flags &= ~VWF_SCROLL; 950256145Sray VTBUF_SLCK_DISABLE(&vw->vw_buf); 951219888Sed } 952219888Sed break; 953257076Sray /* XXX: KDB can handle history. */ 954257076Sray case SPCLKEY | FKEY | F(50): /* Arrow up. */ 955257076Sray vw->vw_kbdsq = "\x1b[A"; 956219888Sed break; 957257076Sray case SPCLKEY | FKEY | F(58): /* Arrow down. */ 958257076Sray vw->vw_kbdsq = "\x1b[B"; 959219888Sed break; 960257076Sray case SPCLKEY | FKEY | F(55): /* Arrow right. */ 961257076Sray vw->vw_kbdsq = "\x1b[C"; 962219888Sed break; 963257076Sray case SPCLKEY | FKEY | F(53): /* Arrow left. */ 964257076Sray vw->vw_kbdsq = "\x1b[D"; 965219888Sed break; 966219888Sed } 967219888Sed 968219888Sed /* Force refresh to make scrollback work. */ 969219888Sed vt_flush(vd); 970219888Sed } else if (KEYFLAGS(c) == 0) { 971258947Sray return (KEYCHAR(c)); 972219888Sed } 973256145Sray 974257076Sray if (vw->vw_kbdsq && *vw->vw_kbdsq) 975258166Sray return (*vw->vw_kbdsq++); 976257076Sray 977219888Sed return (-1); 978219888Sed} 979219888Sed 980219888Sedstatic void 981219888Sedvtterm_opened(struct terminal *tm, int opened) 982219888Sed{ 983219888Sed struct vt_window *vw = tm->tm_softc; 984219888Sed struct vt_device *vd = vw->vw_device; 985219888Sed 986219888Sed VT_LOCK(vd); 987219888Sed vd->vd_flags &= ~VDF_SPLASH; 988219888Sed if (opened) 989258408Sray vw->vw_flags |= VWF_OPENED; 990256145Sray else { 991258408Sray vw->vw_flags &= ~VWF_OPENED; 992256145Sray /* TODO: finish ACQ/REL */ 993256145Sray } 994219888Sed VT_UNLOCK(vd); 995219888Sed} 996219888Sed 997219888Sedstatic int 998219888Sedvt_change_font(struct vt_window *vw, struct vt_font *vf) 999219888Sed{ 1000219888Sed struct vt_device *vd = vw->vw_device; 1001219888Sed struct terminal *tm = vw->vw_terminal; 1002219888Sed term_pos_t size; 1003219888Sed struct winsize wsz; 1004219888Sed 1005219888Sed /* 1006219888Sed * Changing fonts. 1007219888Sed * 1008219888Sed * Changing fonts is a little tricky. We must prevent 1009219888Sed * simultaneous access to the device, so we must stop 1010219888Sed * the display timer and the terminal from accessing. 1011219888Sed * We need to switch fonts and grow our screen buffer. 1012219888Sed * 1013219888Sed * XXX: Right now the code uses terminal_mute() to 1014219888Sed * prevent data from reaching the console driver while 1015219888Sed * resizing the screen buffer. This isn't elegant... 1016219888Sed */ 1017219888Sed 1018219888Sed VT_LOCK(vd); 1019219888Sed if (vw->vw_flags & VWF_BUSY) { 1020219888Sed /* Another process is changing the font. */ 1021219888Sed VT_UNLOCK(vd); 1022219888Sed return (EBUSY); 1023219888Sed } 1024219888Sed if (vw->vw_font == NULL) { 1025219888Sed /* Our device doesn't need fonts. */ 1026219888Sed VT_UNLOCK(vd); 1027219888Sed return (ENOTTY); 1028219888Sed } 1029258408Sray vw->vw_flags |= VWF_BUSY; 1030219888Sed VT_UNLOCK(vd); 1031219888Sed 1032219888Sed vt_termsize(vd, vf, &size); 1033219888Sed vt_winsize(vd, vf, &wsz); 1034257978Sray /* Save offset to font aligned area. */ 1035257978Sray vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2; 1036257978Sray vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2; 1037219888Sed 1038219888Sed /* Grow the screen buffer and terminal. */ 1039219888Sed terminal_mute(tm, 1); 1040256145Sray vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size); 1041256903Sray terminal_set_winsize_blank(tm, &wsz, 0); 1042219888Sed terminal_mute(tm, 0); 1043219888Sed 1044219888Sed /* Actually apply the font to the current window. */ 1045219888Sed VT_LOCK(vd); 1046219888Sed vtfont_unref(vw->vw_font); 1047219888Sed vw->vw_font = vtfont_ref(vf); 1048219888Sed 1049219888Sed /* Force a full redraw the next timer tick. */ 1050219888Sed if (vd->vd_curwindow == vw) 1051219888Sed vd->vd_flags |= VDF_INVALID; 1052258408Sray vw->vw_flags &= ~VWF_BUSY; 1053219888Sed VT_UNLOCK(vd); 1054219888Sed return (0); 1055219888Sed} 1056219888Sed 1057219888Sedstatic int 1058263817Srayvt_set_border(struct vt_window *vw, struct vt_font *vf, term_color_t c) 1059263817Sray{ 1060263817Sray struct vt_device *vd = vw->vw_device; 1061263817Sray int l, r, t, b, w, h; 1062263817Sray 1063263817Sray if (vd->vd_driver->vd_drawrect == NULL) 1064263817Sray return (ENOTSUP); 1065263817Sray 1066263817Sray w = vd->vd_width - 1; 1067263817Sray h = vd->vd_height - 1; 1068263817Sray l = vd->vd_offset.tp_col - 1; 1069263817Sray r = w - l; 1070263817Sray t = vd->vd_offset.tp_row - 1; 1071263817Sray b = h - t; 1072263817Sray 1073263817Sray vd->vd_driver->vd_drawrect(vd, 0, 0, w, t, 1, c); /* Top bar. */ 1074263817Sray vd->vd_driver->vd_drawrect(vd, 0, t, l, b, 1, c); /* Left bar. */ 1075263817Sray vd->vd_driver->vd_drawrect(vd, r, t, w, b, 1, c); /* Right bar. */ 1076263817Sray vd->vd_driver->vd_drawrect(vd, 0, b, w, h, 1, c); /* Bottom bar. */ 1077263817Sray 1078263817Sray return (0); 1079263817Sray} 1080263817Sray 1081263817Sraystatic int 1082256145Srayvt_proc_alive(struct vt_window *vw) 1083256145Sray{ 1084256145Sray struct proc *p; 1085256145Sray 1086256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1087258947Sray return (FALSE); 1088256145Sray 1089256145Sray if (vw->vw_proc) { 1090256145Sray if ((p = pfind(vw->vw_pid)) != NULL) 1091256145Sray PROC_UNLOCK(p); 1092256145Sray if (vw->vw_proc == p) 1093258947Sray return (TRUE); 1094256145Sray vw->vw_proc = NULL; 1095256145Sray vw->vw_smode.mode = VT_AUTO; 1096256145Sray DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid); 1097256145Sray vw->vw_pid = 0; 1098256145Sray } 1099258947Sray return (FALSE); 1100256145Sray} 1101256145Sray 1102256145Sraystatic int 1103256145Sraysignal_vt_rel(struct vt_window *vw) 1104256145Sray{ 1105257815Sray 1106256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1107258947Sray return (FALSE); 1108256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1109256145Sray vw->vw_proc = NULL; 1110256145Sray vw->vw_pid = 0; 1111258947Sray return (TRUE); 1112256145Sray } 1113258408Sray vw->vw_flags |= VWF_SWWAIT_REL; 1114256145Sray PROC_LOCK(vw->vw_proc); 1115256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.relsig); 1116256145Sray PROC_UNLOCK(vw->vw_proc); 1117256145Sray DPRINTF(1, "sending relsig to %d\n", vw->vw_pid); 1118258947Sray return (TRUE); 1119256145Sray} 1120256145Sray 1121256145Sraystatic int 1122256145Sraysignal_vt_acq(struct vt_window *vw) 1123256145Sray{ 1124257815Sray 1125256145Sray if (vw->vw_smode.mode != VT_PROCESS) 1126258947Sray return (FALSE); 1127256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1128256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1129256145Sray if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) { 1130256145Sray vw->vw_proc = NULL; 1131256145Sray vw->vw_pid = 0; 1132258947Sray return (TRUE); 1133256145Sray } 1134258408Sray vw->vw_flags |= VWF_SWWAIT_ACQ; 1135256145Sray PROC_LOCK(vw->vw_proc); 1136256145Sray kern_psignal(vw->vw_proc, vw->vw_smode.acqsig); 1137256145Sray PROC_UNLOCK(vw->vw_proc); 1138256145Sray DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid); 1139258947Sray return (TRUE); 1140256145Sray} 1141256145Sray 1142256145Sraystatic int 1143256145Srayfinish_vt_rel(struct vt_window *vw, int release, int *s) 1144256145Sray{ 1145257815Sray 1146256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1147258408Sray vw->vw_flags &= ~VWF_SWWAIT_REL; 1148256145Sray if (release) { 1149256145Sray callout_drain(&vw->vw_proc_dead_timer); 1150256145Sray vt_late_window_switch(vw->vw_switch_to); 1151256145Sray } 1152258947Sray return (0); 1153256145Sray } 1154258947Sray return (EINVAL); 1155256145Sray} 1156256145Sray 1157256145Sraystatic int 1158256145Srayfinish_vt_acq(struct vt_window *vw) 1159256145Sray{ 1160257815Sray 1161256145Sray if (vw->vw_flags & VWF_SWWAIT_ACQ) { 1162258408Sray vw->vw_flags &= ~VWF_SWWAIT_ACQ; 1163258947Sray return (0); 1164256145Sray } 1165258947Sray return (EINVAL); 1166256145Sray} 1167256145Sray 1168263817Sray#ifndef SC_NO_CUTPASTE 1169263817Sraystatic void 1170263817Srayvt_mouse_terminput_button(struct vt_device *vd, int button) 1171263817Sray{ 1172263817Sray struct vt_window *vw; 1173263817Sray struct vt_font *vf; 1174263817Sray char mouseb[6] = "\x1B[M"; 1175263817Sray int i, x, y; 1176263817Sray 1177263817Sray vw = vd->vd_curwindow; 1178263817Sray vf = vw->vw_font; 1179263817Sray 1180263817Sray /* Translate to char position. */ 1181263817Sray x = vd->vd_mx / vf->vf_width; 1182263817Sray y = vd->vd_my / vf->vf_height; 1183263817Sray /* Avoid overflow. */ 1184263817Sray x = MIN(x, 255 - '!'); 1185263817Sray y = MIN(y, 255 - '!'); 1186263817Sray 1187263817Sray mouseb[3] = ' ' + button; 1188263817Sray mouseb[4] = '!' + x; 1189263817Sray mouseb[5] = '!' + y; 1190263817Sray 1191263817Sray for (i = 0; i < sizeof(mouseb); i++ ) 1192263817Sray terminal_input_char(vw->vw_terminal, mouseb[i]); 1193263817Sray} 1194263817Sray 1195263817Sraystatic void 1196263817Srayvt_mouse_terminput(struct vt_device *vd, int type, int x, int y, int event, 1197263817Sray int cnt) 1198263817Sray{ 1199263817Sray 1200263817Sray switch (type) { 1201263817Sray case MOUSE_BUTTON_EVENT: 1202263817Sray if (cnt > 0) { 1203263817Sray /* Mouse button pressed. */ 1204263817Sray if (event & MOUSE_BUTTON1DOWN) 1205263817Sray vt_mouse_terminput_button(vd, 0); 1206263817Sray if (event & MOUSE_BUTTON2DOWN) 1207263817Sray vt_mouse_terminput_button(vd, 1); 1208263817Sray if (event & MOUSE_BUTTON3DOWN) 1209263817Sray vt_mouse_terminput_button(vd, 2); 1210263817Sray } else { 1211263817Sray /* Mouse button released. */ 1212263817Sray vt_mouse_terminput_button(vd, 3); 1213263817Sray } 1214263817Sray break; 1215263817Sray#ifdef notyet 1216263817Sray case MOUSE_MOTION_EVENT: 1217263817Sray if (mouse->u.data.z < 0) { 1218263817Sray /* Scroll up. */ 1219263817Sray sc_mouse_input_button(vd, 64); 1220263817Sray } else if (mouse->u.data.z > 0) { 1221263817Sray /* Scroll down. */ 1222263817Sray sc_mouse_input_button(vd, 65); 1223263817Sray } 1224263817Sray break; 1225263817Sray#endif 1226263817Sray } 1227263817Sray} 1228263817Sray 1229257977Srayvoid 1230263817Srayvt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel) 1231257977Sray{ 1232257977Sray struct vt_device *vd; 1233257977Sray struct vt_window *vw; 1234257977Sray struct vt_font *vf; 1235257977Sray term_pos_t size; 1236258090Sray term_char_t *buf; 1237258090Sray int i, len, mark; 1238257977Sray 1239257977Sray vd = main_vd; 1240257977Sray vw = vd->vd_curwindow; 1241257977Sray vf = vw->vw_font; 1242258781Snwhitehorn mark = 0; 1243257977Sray 1244258327Sray if (vw->vw_flags & VWF_MOUSE_HIDE) 1245258327Sray return; /* Mouse disabled. */ 1246258327Sray 1247257977Sray if (vf == NULL) /* Text mode. */ 1248257977Sray return; 1249257977Sray 1250257977Sray /* 1251257977Sray * TODO: add flag about pointer position changed, to not redraw chars 1252257977Sray * under mouse pointer when nothing changed. 1253257977Sray */ 1254257977Sray 1255263817Sray if (vw->vw_mouse_level > 0) 1256263817Sray vt_mouse_terminput(vd, type, x, y, event, cnt); 1257263817Sray 1258257977Sray switch (type) { 1259257977Sray case MOUSE_ACTION: 1260257977Sray case MOUSE_MOTION_EVENT: 1261257977Sray /* Movement */ 1262257977Sray x += vd->vd_mx; 1263257977Sray y += vd->vd_my; 1264257977Sray 1265257977Sray vt_termsize(vd, vf, &size); 1266257977Sray 1267257977Sray /* Apply limits. */ 1268257977Sray x = MAX(x, 0); 1269257977Sray y = MAX(y, 0); 1270257977Sray x = MIN(x, (size.tp_col * vf->vf_width) - 1); 1271257977Sray y = MIN(y, (size.tp_row * vf->vf_height) - 1); 1272257977Sray 1273257977Sray vd->vd_mx = x; 1274257977Sray vd->vd_my = y; 1275258090Sray if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) && 1276258130Sray (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE, 1277258090Sray vd->vd_mx / vf->vf_width, 1278258090Sray vd->vd_my / vf->vf_height) == 1)) { 1279258090Sray 1280258090Sray /* 1281258090Sray * We have something marked to copy, so update pointer 1282258090Sray * to window with selection. 1283258090Sray */ 1284258090Sray vd->vd_markedwin = vw; 1285258090Sray } 1286257977Sray return; /* Done */ 1287257977Sray case MOUSE_BUTTON_EVENT: 1288257977Sray /* Buttons */ 1289257977Sray break; 1290257977Sray default: 1291257977Sray return; /* Done */ 1292257977Sray } 1293257977Sray 1294257977Sray switch (event) { 1295257977Sray case MOUSE_BUTTON1DOWN: 1296257977Sray switch (cnt % 4) { 1297257977Sray case 0: /* up */ 1298257977Sray mark = VTB_MARK_END; 1299257977Sray break; 1300257977Sray case 1: /* single click: start cut operation */ 1301257977Sray mark = VTB_MARK_START; 1302257977Sray break; 1303257977Sray case 2: /* double click: cut a word */ 1304257977Sray mark = VTB_MARK_WORD; 1305257977Sray break; 1306257977Sray case 3: /* triple click: cut a line */ 1307257977Sray mark = VTB_MARK_ROW; 1308257977Sray break; 1309257977Sray } 1310257977Sray break; 1311257977Sray case VT_MOUSE_PASTEBUTTON: 1312258112Sray switch (cnt) { 1313257977Sray case 0: /* up */ 1314257977Sray break; 1315257977Sray default: 1316258090Sray if (vd->vd_markedwin == NULL) 1317258090Sray return; 1318258090Sray /* Get current selecton size in bytes. */ 1319258090Sray len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf); 1320258090Sray if (len <= 0) 1321258090Sray return; 1322258090Sray 1323258090Sray buf = malloc(len, M_VT, M_WAITOK | M_ZERO); 1324258090Sray /* Request cupy/paste buffer data, no more than `len' */ 1325258090Sray vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf, 1326258090Sray len); 1327258090Sray 1328258090Sray len /= sizeof(term_char_t); 1329258090Sray for (i = 0; i < len; i++ ) { 1330258090Sray if (buf[i] == '\0') 1331258090Sray continue; 1332258090Sray terminal_input_char(vw->vw_terminal, buf[i]); 1333258090Sray } 1334258090Sray 1335258090Sray /* Done, so cleanup. */ 1336258090Sray free(buf, M_VT); 1337257977Sray break; 1338257977Sray } 1339257977Sray return; /* Done */ 1340257977Sray case VT_MOUSE_EXTENDBUTTON: 1341258112Sray switch (cnt) { 1342257977Sray case 0: /* up */ 1343257977Sray if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN)) 1344258130Sray mark = VTB_MARK_EXTEND; 1345257977Sray else 1346257977Sray mark = 0; 1347257977Sray break; 1348257977Sray default: 1349257977Sray mark = VTB_MARK_EXTEND; 1350257977Sray break; 1351257977Sray } 1352257977Sray break; 1353257977Sray default: 1354257977Sray return; /* Done */ 1355257977Sray } 1356257977Sray 1357257977Sray /* Save buttons state. */ 1358257977Sray if (cnt > 0) 1359257977Sray vd->vd_mstate |= event; 1360257977Sray else 1361257977Sray vd->vd_mstate &= ~event; 1362257977Sray 1363258090Sray if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, 1364258090Sray vd->vd_my / vf->vf_height) == 1) { 1365258090Sray /* 1366258090Sray * We have something marked to copy, so update pointer to 1367258090Sray * window with selection. 1368258090Sray */ 1369258090Sray vd->vd_markedwin = vw; 1370258090Sray } 1371257977Sray} 1372257977Sray 1373258327Srayvoid 1374258327Srayvt_mouse_state(int show) 1375258327Sray{ 1376258327Sray struct vt_device *vd; 1377258327Sray struct vt_window *vw; 1378258327Sray 1379258327Sray vd = main_vd; 1380258327Sray vw = vd->vd_curwindow; 1381258327Sray 1382258327Sray switch (show) { 1383258327Sray case VT_MOUSE_HIDE: 1384258409Sray vw->vw_flags |= VWF_MOUSE_HIDE; 1385258327Sray break; 1386258327Sray case VT_MOUSE_SHOW: 1387258409Sray vw->vw_flags &= ~VWF_MOUSE_HIDE; 1388258327Sray break; 1389258327Sray } 1390258327Sray} 1391263817Sray#endif 1392258327Sray 1393256145Sraystatic int 1394263817Srayvtterm_mmap(struct terminal *tm, vm_ooffset_t offset, vm_paddr_t * paddr, 1395263817Sray int nprot, vm_memattr_t *memattr) 1396263817Sray{ 1397263817Sray struct vt_window *vw = tm->tm_softc; 1398263817Sray struct vt_device *vd = vw->vw_device; 1399263817Sray 1400263817Sray if (vd->vd_driver->vd_fb_mmap) 1401263817Sray return (vd->vd_driver->vd_fb_mmap(vd, offset, paddr, nprot, 1402263817Sray memattr)); 1403263817Sray 1404263817Sray return (ENXIO); 1405263817Sray} 1406263817Sray 1407263817Sraystatic int 1408219888Sedvtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, 1409219888Sed struct thread *td) 1410219888Sed{ 1411219888Sed struct vt_window *vw = tm->tm_softc; 1412219888Sed struct vt_device *vd = vw->vw_device; 1413258947Sray keyboard_t *kbd; 1414258947Sray int error, i, s; 1415258947Sray#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 1416258947Sray defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 1417258947Sray int ival; 1418219888Sed 1419219888Sed switch (cmd) { 1420258947Sray case _IO('v', 4): 1421258947Sray cmd = VT_RELDISP; 1422258947Sray break; 1423258947Sray case _IO('v', 5): 1424258947Sray cmd = VT_ACTIVATE; 1425258947Sray break; 1426258947Sray case _IO('v', 6): 1427258947Sray cmd = VT_WAITACTIVE; 1428258947Sray break; 1429258947Sray case _IO('K', 20): 1430258947Sray cmd = KDSKBSTATE; 1431258947Sray break; 1432258947Sray case _IO('K', 67): 1433258947Sray cmd = KDSETRAD; 1434258947Sray break; 1435258947Sray case _IO('K', 7): 1436258947Sray cmd = KDSKBMODE; 1437258947Sray break; 1438258947Sray case _IO('K', 8): 1439258947Sray cmd = KDMKTONE; 1440258947Sray break; 1441258947Sray case _IO('K', 63): 1442258947Sray cmd = KIOCSOUND; 1443258947Sray break; 1444258947Sray case _IO('K', 66): 1445258947Sray cmd = KDSETLED; 1446258947Sray break; 1447258947Sray case _IO('c', 110): 1448258947Sray cmd = CONS_SETKBD; 1449258947Sray break; 1450263817Sray default: 1451263817Sray goto skip_thunk; 1452258947Sray } 1453258947Sray ival = IOCPARM_IVAL(data); 1454258947Sray data = (caddr_t)&ival; 1455263817Srayskip_thunk: 1456258947Sray#endif 1457258947Sray 1458258947Sray switch (cmd) { 1459258947Sray case KDSETRAD: /* set keyboard repeat & delay rates (old) */ 1460258947Sray if (*(int *)data & ~0x7f) 1461258947Sray return (EINVAL); 1462219888Sed case GIO_KEYMAP: 1463219888Sed case PIO_KEYMAP: 1464219888Sed case GIO_DEADKEYMAP: 1465219888Sed case PIO_DEADKEYMAP: 1466219888Sed case GETFKEY: 1467219888Sed case SETFKEY: 1468258947Sray case KDGKBINFO: 1469258947Sray case KDGKBTYPE: 1470258947Sray case KDSKBSTATE: /* set keyboard state (locks) */ 1471258947Sray case KDGKBSTATE: /* get keyboard state (locks) */ 1472258947Sray case KDGETREPEAT: /* get keyboard repeat & delay rates */ 1473258947Sray case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ 1474258947Sray case KDSETLED: /* set keyboard LED status */ 1475258947Sray case KDGETLED: /* get keyboard LED status */ 1476258947Sray case KBADDKBD: /* add/remove keyboard to/from mux */ 1477258947Sray case KBRELKBD: { 1478256145Sray error = 0; 1479219888Sed 1480219888Sed mtx_lock(&Giant); 1481219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1482219888Sed if (kbd != NULL) 1483219888Sed error = kbdd_ioctl(kbd, cmd, data); 1484219888Sed mtx_unlock(&Giant); 1485258947Sray if (error == ENOIOCTL) { 1486258947Sray if (cmd == KDGKBTYPE) { 1487258947Sray /* always return something? XXX */ 1488258947Sray *(int *)data = 0; 1489258947Sray } else { 1490258947Sray return (ENODEV); 1491258947Sray } 1492258947Sray } 1493219888Sed return (error); 1494219888Sed } 1495256145Sray case KDGKBMODE: { 1496256145Sray int mode = -1; 1497256145Sray 1498256145Sray mtx_lock(&Giant); 1499256145Sray kbd = kbd_get_keyboard(vd->vd_keyboard); 1500256145Sray if (kbd != NULL) { 1501256145Sray kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode); 1502256145Sray } 1503256145Sray mtx_unlock(&Giant); 1504256145Sray DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode); 1505256145Sray *(int *)data = mode; 1506256145Sray return (0); 1507256145Sray } 1508219888Sed case KDSKBMODE: { 1509219888Sed int mode; 1510219888Sed 1511219888Sed mode = *(int *)data; 1512219888Sed switch (mode) { 1513219888Sed case K_XLATE: 1514219888Sed case K_RAW: 1515219888Sed case K_CODE: 1516219888Sed vw->vw_kbdmode = mode; 1517219888Sed if (vw == vd->vd_curwindow) { 1518219888Sed keyboard_t *kbd; 1519256145Sray error = 0; 1520219888Sed 1521219888Sed mtx_lock(&Giant); 1522219888Sed kbd = kbd_get_keyboard(vd->vd_keyboard); 1523256145Sray if (kbd != NULL) { 1524256145Sray error = kbdd_ioctl(kbd, KDSKBMODE, 1525219888Sed (void *)&mode); 1526256145Sray } 1527219888Sed mtx_unlock(&Giant); 1528219888Sed } 1529219888Sed return (0); 1530219888Sed default: 1531219888Sed return (EINVAL); 1532219888Sed } 1533219888Sed } 1534263817Sray case FBIOGTYPE: 1535263817Sray case FBIO_GETWINORG: /* get frame buffer window origin */ 1536263817Sray case FBIO_GETDISPSTART: /* get display start address */ 1537263817Sray case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 1538263817Sray case FBIO_BLANK: /* blank display */ 1539263817Sray if (vd->vd_driver->vd_fb_ioctl) 1540263817Sray return (vd->vd_driver->vd_fb_ioctl(vd, cmd, data, td)); 1541263817Sray break; 1542219888Sed case CONS_BLANKTIME: 1543219888Sed /* XXX */ 1544219888Sed return (0); 1545219888Sed case CONS_GET: 1546219888Sed /* XXX */ 1547219888Sed *(int *)data = M_CG640x480; 1548219888Sed return (0); 1549263817Sray case CONS_BELLTYPE: /* set bell type sound */ 1550263817Sray if ((*(int *)data) & CONS_QUIET_BELL) 1551263817Sray vd->vd_flags |= VDF_QUIET_BELL; 1552263817Sray else 1553263817Sray vd->vd_flags &= ~VDF_QUIET_BELL; 1554263817Sray return (0); 1555219888Sed case CONS_GETINFO: { 1556219888Sed vid_info_t *vi = (vid_info_t *)data; 1557219888Sed 1558219888Sed vi->m_num = vd->vd_curwindow->vw_number + 1; 1559219888Sed /* XXX: other fields! */ 1560219888Sed return (0); 1561219888Sed } 1562219888Sed case CONS_GETVERS: 1563219888Sed *(int *)data = 0x200; 1564258947Sray return (0); 1565219888Sed case CONS_MODEINFO: 1566219888Sed /* XXX */ 1567219888Sed return (0); 1568219888Sed case CONS_MOUSECTL: { 1569219888Sed mouse_info_t *mouse = (mouse_info_t*)data; 1570219888Sed 1571219888Sed /* 1572219888Sed * This has no effect on vt(4). We don't draw any mouse 1573219888Sed * cursor. Just ignore MOUSE_HIDE and MOUSE_SHOW to 1574219888Sed * prevent excessive errors. All the other commands 1575219888Sed * should not be applied to individual TTYs, but only to 1576219888Sed * consolectl. 1577219888Sed */ 1578219888Sed switch (mouse->operation) { 1579219888Sed case MOUSE_HIDE: 1580257982Sray vd->vd_flags &= ~VDF_MOUSECURSOR; 1581257982Sray return (0); 1582219888Sed case MOUSE_SHOW: 1583257982Sray vd->vd_mx = vd->vd_width / 2; 1584257982Sray vd->vd_my = vd->vd_height / 2; 1585257982Sray vd->vd_flags |= VDF_MOUSECURSOR; 1586219888Sed return (0); 1587219888Sed default: 1588219888Sed return (EINVAL); 1589219888Sed } 1590219888Sed } 1591219888Sed case PIO_VFONT: { 1592219888Sed struct vt_font *vf; 1593219888Sed 1594219888Sed error = vtfont_load((void *)data, &vf); 1595219888Sed if (error != 0) 1596219888Sed return (error); 1597219888Sed 1598219888Sed error = vt_change_font(vw, vf); 1599263817Sray if (error == 0) { 1600263817Sray /* XXX: replace 0 with current bg color. */ 1601263817Sray vt_set_border(vw, vf, 0); 1602263817Sray } 1603219888Sed vtfont_unref(vf); 1604219888Sed return (error); 1605219888Sed } 1606219888Sed case GIO_SCRNMAP: { 1607219888Sed scrmap_t *sm = (scrmap_t *)data; 1608219888Sed int i; 1609219888Sed 1610219888Sed /* We don't have screen maps, so return a handcrafted one. */ 1611219888Sed for (i = 0; i < 256; i++) 1612219888Sed sm->scrmap[i] = i; 1613219888Sed return (0); 1614219888Sed } 1615258947Sray case KDSETMODE: 1616219888Sed /* XXX */ 1617219888Sed return (0); 1618258947Sray case KDENABIO: /* allow io operations */ 1619258947Sray error = priv_check(td, PRIV_IO); 1620258947Sray if (error != 0) 1621258947Sray return (error); 1622258947Sray error = securelevel_gt(td->td_ucred, 0); 1623258947Sray if (error != 0) 1624258947Sray return (error); 1625263817Sray#if defined(__i386__) 1626263817Sray td->td_frame->tf_eflags |= PSL_IOPL; 1627263817Sray#elif defined(__amd64__) 1628258947Sray td->td_frame->tf_rflags |= PSL_IOPL; 1629258947Sray#endif 1630219888Sed return (0); 1631258947Sray case KDDISABIO: /* disallow io operations (default) */ 1632263817Sray#if defined(__i386__) 1633263817Sray td->td_frame->tf_eflags &= ~PSL_IOPL; 1634263817Sray#elif defined(__amd64__) 1635258947Sray td->td_frame->tf_rflags &= ~PSL_IOPL; 1636258947Sray#endif 1637219888Sed return (0); 1638258947Sray case KDMKTONE: /* sound the bell */ 1639258947Sray /* TODO */ 1640219888Sed return (0); 1641258947Sray case KIOCSOUND: /* make tone (*data) hz */ 1642258947Sray /* TODO */ 1643258947Sray return (0); 1644258947Sray case CONS_SETKBD: /* set the new keyboard */ 1645258947Sray mtx_lock(&Giant); 1646258947Sray error = 0; 1647258947Sray if (vd->vd_keyboard != *(int *)data) { 1648258947Sray kbd = kbd_get_keyboard(*(int *)data); 1649258947Sray if (kbd == NULL) { 1650258947Sray mtx_unlock(&Giant); 1651258947Sray return (EINVAL); 1652258947Sray } 1653258947Sray i = kbd_allocate(kbd->kb_name, kbd->kb_unit, 1654258947Sray (void *)&vd->vd_keyboard, vt_kbdevent, vd); 1655258947Sray if (i >= 0) { 1656258947Sray if (vd->vd_keyboard != -1) { 1657258947Sray kbd_release(kbd, 1658258947Sray (void *)&vd->vd_keyboard); 1659258947Sray } 1660258947Sray kbd = kbd_get_keyboard(i); 1661258947Sray vd->vd_keyboard = i; 1662258947Sray 1663258947Sray (void)kbdd_ioctl(kbd, KDSKBMODE, 1664258947Sray (caddr_t)&vd->vd_curwindow->vw_kbdmode); 1665258947Sray } else { 1666258947Sray error = EPERM; /* XXX */ 1667258947Sray } 1668258947Sray } 1669258947Sray mtx_unlock(&Giant); 1670258947Sray return (error); 1671258947Sray case CONS_RELKBD: /* release the current keyboard */ 1672258947Sray mtx_lock(&Giant); 1673258947Sray error = 0; 1674258947Sray if (vd->vd_keyboard != -1) { 1675258947Sray kbd = kbd_get_keyboard(vd->vd_keyboard); 1676258947Sray if (kbd == NULL) { 1677258947Sray mtx_unlock(&Giant); 1678258947Sray return (EINVAL); 1679258947Sray } 1680258947Sray error = kbd_release(kbd, (void *)&vd->vd_keyboard); 1681258947Sray if (error == 0) { 1682258947Sray vd->vd_keyboard = -1; 1683258947Sray } 1684258947Sray } 1685258947Sray mtx_unlock(&Giant); 1686258947Sray return (error); 1687256145Sray case VT_ACTIVATE: { 1688256145Sray int win; 1689256145Sray win = *(int *)data - 1; 1690258947Sray DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, 1691258947Sray VT_UNIT(vw), win); 1692256145Sray if ((win > VT_MAXWINDOWS) || (win < 0)) 1693256145Sray return (EINVAL); 1694256145Sray return (vt_proc_window_switch(vd->vd_windows[win])); 1695256145Sray } 1696219888Sed case VT_GETACTIVE: 1697219888Sed *(int *)data = vd->vd_curwindow->vw_number + 1; 1698219888Sed return (0); 1699219888Sed case VT_GETINDEX: 1700219888Sed *(int *)data = vw->vw_number + 1; 1701219888Sed return (0); 1702256145Sray case VT_LOCKSWITCH: 1703256145Sray /* TODO: Check current state, switching can be in progress. */ 1704256145Sray if ((*(int *)data) & 0x01) 1705258408Sray vw->vw_flags |= VWF_VTYLOCK; 1706256145Sray else 1707258408Sray vw->vw_flags &= ~VWF_VTYLOCK; 1708258947Sray case VT_OPENQRY: 1709219888Sed VT_LOCK(vd); 1710219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1711219888Sed vw = vd->vd_windows[i]; 1712219888Sed if (vw == NULL) 1713219888Sed continue; 1714219888Sed if (!(vw->vw_flags & VWF_OPENED)) { 1715219888Sed *(int *)data = vw->vw_number + 1; 1716219888Sed VT_UNLOCK(vd); 1717219888Sed return (0); 1718219888Sed } 1719219888Sed } 1720219888Sed VT_UNLOCK(vd); 1721219888Sed return (EINVAL); 1722279265Sdelphij case VT_WAITACTIVE: { 1723279265Sdelphij unsigned int idx; 1724279265Sdelphij 1725256145Sray error = 0; 1726219888Sed 1727279265Sdelphij idx = *(unsigned int *)data; 1728279265Sdelphij if (idx > VT_MAXWINDOWS) 1729219888Sed return (EINVAL); 1730279265Sdelphij if (idx > 0) 1731279265Sdelphij vw = vd->vd_windows[idx - 1]; 1732219888Sed 1733219888Sed VT_LOCK(vd); 1734219888Sed while (vd->vd_curwindow != vw && error == 0) 1735219888Sed error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock); 1736219888Sed VT_UNLOCK(vd); 1737219888Sed return (error); 1738279265Sdelphij } 1739258947Sray case VT_SETMODE: { /* set screen switcher mode */ 1740256145Sray struct vt_mode *mode; 1741256145Sray struct proc *p1; 1742256145Sray 1743256145Sray mode = (struct vt_mode *)data; 1744256145Sray DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw)); 1745256145Sray if (vw->vw_smode.mode == VT_PROCESS) { 1746256145Sray p1 = pfind(vw->vw_pid); 1747256145Sray if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) { 1748256145Sray if (p1) 1749256145Sray PROC_UNLOCK(p1); 1750256145Sray DPRINTF(5, "error EPERM\n"); 1751256145Sray return (EPERM); 1752256145Sray } 1753256145Sray if (p1) 1754256145Sray PROC_UNLOCK(p1); 1755256145Sray } 1756256145Sray if (mode->mode == VT_AUTO) { 1757256145Sray vw->vw_smode.mode = VT_AUTO; 1758256145Sray vw->vw_proc = NULL; 1759256145Sray vw->vw_pid = 0; 1760256145Sray DPRINTF(5, "VT_AUTO, "); 1761256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1762256145Sray cnavailable(vw->vw_terminal->consdev, TRUE); 1763256145Sray /* were we in the middle of the vty switching process? */ 1764256145Sray if (finish_vt_rel(vw, TRUE, &s) == 0) 1765256145Sray DPRINTF(5, "reset WAIT_REL, "); 1766256145Sray if (finish_vt_acq(vw) == 0) 1767256145Sray DPRINTF(5, "reset WAIT_ACQ, "); 1768256145Sray return (0); 1769256145Sray } else if (mode->mode == VT_PROCESS) { 1770256145Sray if (!ISSIGVALID(mode->relsig) || 1771256145Sray !ISSIGVALID(mode->acqsig) || 1772256145Sray !ISSIGVALID(mode->frsig)) { 1773256145Sray DPRINTF(5, "error EINVAL\n"); 1774256145Sray return (EINVAL); 1775256145Sray } 1776256145Sray DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid); 1777256145Sray bcopy(data, &vw->vw_smode, sizeof(struct vt_mode)); 1778256145Sray vw->vw_proc = td->td_proc; 1779256145Sray vw->vw_pid = vw->vw_proc->p_pid; 1780256145Sray if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW]) 1781256145Sray cnavailable(vw->vw_terminal->consdev, FALSE); 1782256145Sray } else { 1783256145Sray DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n", 1784256145Sray mode->mode); 1785256145Sray return (EINVAL); 1786256145Sray } 1787256145Sray DPRINTF(5, "\n"); 1788258947Sray return (0); 1789219888Sed } 1790256145Sray case VT_GETMODE: /* get screen switcher mode */ 1791256145Sray bcopy(&vw->vw_smode, data, sizeof(struct vt_mode)); 1792258947Sray return (0); 1793256145Sray 1794256145Sray case VT_RELDISP: /* screen switcher ioctl */ 1795256145Sray /* 1796256145Sray * This must be the current vty which is in the VT_PROCESS 1797256145Sray * switching mode... 1798256145Sray */ 1799256145Sray if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode != 1800256145Sray VT_PROCESS)) { 1801258947Sray return (EINVAL); 1802256145Sray } 1803256145Sray /* ...and this process is controlling it. */ 1804256145Sray if (vw->vw_proc != td->td_proc) { 1805258947Sray return (EPERM); 1806256145Sray } 1807256145Sray error = EINVAL; 1808256145Sray switch(*(int *)data) { 1809256145Sray case VT_FALSE: /* user refuses to release screen, abort */ 1810256145Sray if ((error = finish_vt_rel(vw, FALSE, &s)) == 0) 1811258947Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", 1812258947Sray SC_DRIVER_NAME, VT_UNIT(vw)); 1813256145Sray break; 1814256145Sray case VT_TRUE: /* user has released screen, go on */ 1815256145Sray /* finish_vt_rel(..., TRUE, ...) should not be locked */ 1816256145Sray if (vw->vw_flags & VWF_SWWAIT_REL) { 1817256145Sray if ((error = finish_vt_rel(vw, TRUE, &s)) == 0) 1818256145Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n", 1819256145Sray SC_DRIVER_NAME, VT_UNIT(vw)); 1820256145Sray } else { 1821256145Sray error = EINVAL; 1822256145Sray } 1823256145Sray return (error); 1824256145Sray case VT_ACKACQ: /* acquire acknowledged, switch completed */ 1825256145Sray if ((error = finish_vt_acq(vw)) == 0) 1826258947Sray DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", 1827258947Sray SC_DRIVER_NAME, VT_UNIT(vw)); 1828256145Sray break; 1829256145Sray default: 1830256145Sray break; 1831256145Sray } 1832258947Sray return (error); 1833256145Sray } 1834256145Sray 1835219888Sed return (ENOIOCTL); 1836219888Sed} 1837219888Sed 1838219888Sedstatic struct vt_window * 1839219888Sedvt_allocate_window(struct vt_device *vd, unsigned int window) 1840219888Sed{ 1841219888Sed struct vt_window *vw; 1842219888Sed struct terminal *tm; 1843219888Sed term_pos_t size; 1844219888Sed struct winsize wsz; 1845219888Sed 1846219888Sed vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO); 1847219888Sed vw->vw_device = vd; 1848219888Sed vw->vw_number = window; 1849219888Sed vw->vw_kbdmode = K_XLATE; 1850219888Sed 1851219888Sed if (!(vd->vd_flags & VDF_TEXTMODE)) 1852219888Sed vw->vw_font = vtfont_ref(&vt_font_default); 1853256145Sray 1854219888Sed vt_termsize(vd, vw->vw_font, &size); 1855219888Sed vt_winsize(vd, vw->vw_font, &wsz); 1856219888Sed vtbuf_init(&vw->vw_buf, &size); 1857219888Sed 1858219888Sed tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw); 1859219888Sed terminal_set_winsize(tm, &wsz); 1860219888Sed vd->vd_windows[window] = vw; 1861256145Sray callout_init(&vw->vw_proc_dead_timer, 0); 1862219888Sed 1863219888Sed return (vw); 1864219888Sed} 1865219888Sed 1866219888Sedvoid 1867219888Sedvt_upgrade(struct vt_device *vd) 1868219888Sed{ 1869219888Sed struct vt_window *vw; 1870219888Sed unsigned int i; 1871219888Sed 1872256145Sray /* Device didn't pass vd_init() or already upgraded. */ 1873256145Sray if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD)) 1874219888Sed return; 1875256145Sray vd->vd_flags |= VDF_ASYNC; 1876219888Sed 1877219888Sed mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); 1878219888Sed cv_init(&vd->vd_winswitch, "vtwswt"); 1879219888Sed 1880256145Sray /* Init 25 Hz timer. */ 1881219888Sed callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); 1882219888Sed 1883219888Sed for (i = 0; i < VT_MAXWINDOWS; i++) { 1884219888Sed vw = vd->vd_windows[i]; 1885219888Sed if (vw == NULL) { 1886219888Sed /* New window. */ 1887219888Sed vw = vt_allocate_window(vd, i); 1888264072Sray } else if (vw->vw_flags & VWF_CONSOLE) { 1889264072Sray /* For existing console window. */ 1890264072Sray callout_init(&vw->vw_proc_dead_timer, 0); 1891256145Sray } 1892256145Sray if (i == VT_CONSWINDOW) { 1893219888Sed /* Console window. */ 1894219888Sed EVENTHANDLER_REGISTER(shutdown_pre_sync, 1895219888Sed vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT); 1896219888Sed } 1897219888Sed terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); 1898264456Sray 1899219888Sed } 1900256145Sray if (vd->vd_curwindow == NULL) 1901256145Sray vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; 1902219888Sed 1903219888Sed /* Attach keyboard. */ 1904219888Sed vt_allocate_keyboard(vd); 1905256145Sray DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); 1906256145Sray 1907256145Sray /* Start timer when everything ready. */ 1908256145Sray callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); 1909219888Sed} 1910219888Sed 1911256145Sraystatic void 1912256145Srayvt_resize(struct vt_device *vd) 1913256145Sray{ 1914256145Sray struct vt_window *vw; 1915256145Sray int i; 1916256145Sray 1917256145Sray for (i = 0; i < VT_MAXWINDOWS; i++) { 1918256145Sray vw = vd->vd_windows[i]; 1919264456Sray /* Assign default font to window, if not textmode. */ 1920264456Sray if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) 1921264456Sray vw->vw_font = vtfont_ref(&vt_font_default); 1922256145Sray /* Resize terminal windows */ 1923256145Sray vt_change_font(vw, vw->vw_font); 1924256145Sray } 1925256145Sray} 1926256145Sray 1927219888Sedvoid 1928219888Sedvt_allocate(struct vt_driver *drv, void *softc) 1929219888Sed{ 1930219888Sed struct vt_device *vd; 1931256903Sray struct winsize wsz; 1932219888Sed 1933256145Sray if (main_vd == NULL) { 1934256145Sray main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); 1935256903Sray printf("%s: VT initialize with new VT driver.\n", __func__); 1936256145Sray } else { 1937256145Sray /* 1938256145Sray * Check if have rights to replace current driver. For example: 1939256145Sray * it is bad idea to replace KMS driver with generic VGA one. 1940256145Sray */ 1941256903Sray if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { 1942256903Sray printf("%s: Driver priority %d too low. Current %d\n ", 1943256903Sray __func__, drv->vd_priority, 1944256903Sray main_vd->vd_driver->vd_priority); 1945256145Sray return; 1946256903Sray } 1947256903Sray printf("%s: Replace existing VT driver.\n", __func__); 1948256145Sray } 1949256145Sray vd = main_vd; 1950264113Sray if (drv->vd_maskbitbltchr == NULL) 1951264113Sray drv->vd_maskbitbltchr = drv->vd_bitbltchr; 1952256145Sray 1953264456Sray if (vd->vd_flags & VDF_ASYNC) { 1954264456Sray /* Stop vt_flush periodic task. */ 1955256145Sray callout_drain(&vd->vd_timer); 1956264456Sray /* 1957264456Sray * Mute current terminal until we done. vt_change_font (called 1958264456Sray * from vt_resize) will unmute it. 1959264456Sray */ 1960264456Sray terminal_mute(vd->vd_curwindow->vw_terminal, 1); 1961264456Sray } 1962256145Sray 1963264456Sray /* 1964264456Sray * Reset VDF_TEXTMODE flag, driver who require that flag (vt_vga) will 1965264456Sray * set it. 1966264456Sray */ 1967264456Sray vd->vd_flags &= ~VDF_TEXTMODE; 1968264456Sray 1969219888Sed vd->vd_driver = drv; 1970219888Sed vd->vd_softc = softc; 1971219888Sed vd->vd_driver->vd_init(vd); 1972256145Sray 1973219888Sed vt_upgrade(vd); 1974256145Sray 1975256145Sray /* Refill settings with new sizes. */ 1976256145Sray vt_resize(vd); 1977256145Sray 1978263817Sray#ifdef DEV_SPLASH 1979256145Sray if (vd->vd_flags & VDF_SPLASH) 1980256145Sray vtterm_splash(vd); 1981263817Sray#endif 1982256145Sray 1983264456Sray if (vd->vd_flags & VDF_ASYNC) { 1984264456Sray terminal_mute(vd->vd_curwindow->vw_terminal, 0); 1985256145Sray callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ); 1986264456Sray } 1987256145Sray 1988256145Sray termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal); 1989256903Sray 1990256903Sray /* Update console window sizes to actual. */ 1991256903Sray vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz); 1992256903Sray terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz); 1993219888Sed} 1994257815Sray 1995257815Srayvoid 1996257815Srayvt_suspend() 1997257815Sray{ 1998257815Sray 1999258023Sray if (vt_suspendswitch == 0) 2000258023Sray return; 2001257815Sray /* Save current window. */ 2002257815Sray main_vd->vd_savedwindow = main_vd->vd_curwindow; 2003257815Sray /* Ask holding process to free window and switch to console window */ 2004257815Sray vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]); 2005257815Sray} 2006257815Sray 2007257815Srayvoid 2008257815Srayvt_resume() 2009257815Sray{ 2010257815Sray 2011258023Sray if (vt_suspendswitch == 0) 2012258023Sray return; 2013257815Sray /* Switch back to saved window */ 2014257815Sray if (main_vd->vd_savedwindow != NULL) 2015257815Sray vt_proc_window_switch(main_vd->vd_savedwindow); 2016257815Sray main_vd->vd_savedwindow = NULL; 2017257815Sray} 2018