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