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