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