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