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