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