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