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