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