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