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