xref: /freebsd/sys/dev/vt/vt_core.c (revision a95ecdf0cfc553f16ab02c4c42d8d56aa8d8e56e)
1 /*-
2  * Copyright (c) 2009, 2013 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Ed Schouten under sponsorship from the
6  * FreeBSD Foundation.
7  *
8  * Portions of this software were developed by Oleksandr Rybalko
9  * under sponsorship from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include "opt_compat.h"
37 
38 #include <sys/param.h>
39 #include <sys/consio.h>
40 #include <sys/eventhandler.h>
41 #include <sys/fbio.h>
42 #include <sys/kbio.h>
43 #include <sys/kdb.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/mutex.h>
48 #include <sys/priv.h>
49 #include <sys/proc.h>
50 #include <sys/reboot.h>
51 #include <sys/systm.h>
52 #include <sys/terminal.h>
53 
54 #include <dev/kbd/kbdreg.h>
55 #include <dev/vt/vt.h>
56 
57 #if defined(__i386__) || defined(__amd64__)
58 #include <machine/psl.h>
59 #include <machine/frame.h>
60 #endif
61 
62 static tc_bell_t	vtterm_bell;
63 static tc_cursor_t	vtterm_cursor;
64 static tc_putchar_t	vtterm_putchar;
65 static tc_fill_t	vtterm_fill;
66 static tc_copy_t	vtterm_copy;
67 static tc_param_t	vtterm_param;
68 static tc_done_t	vtterm_done;
69 
70 static tc_cnprobe_t	vtterm_cnprobe;
71 static tc_cngetc_t	vtterm_cngetc;
72 
73 static tc_opened_t	vtterm_opened;
74 static tc_ioctl_t	vtterm_ioctl;
75 
76 const struct terminal_class vt_termclass = {
77 	.tc_bell	= vtterm_bell,
78 	.tc_cursor	= vtterm_cursor,
79 	.tc_putchar	= vtterm_putchar,
80 	.tc_fill	= vtterm_fill,
81 	.tc_copy	= vtterm_copy,
82 	.tc_param	= vtterm_param,
83 	.tc_done	= vtterm_done,
84 
85 	.tc_cnprobe	= vtterm_cnprobe,
86 	.tc_cngetc	= vtterm_cngetc,
87 
88 	.tc_opened	= vtterm_opened,
89 	.tc_ioctl	= vtterm_ioctl,
90 };
91 
92 /*
93  * Use a constant timer of 25 Hz to redraw the screen.
94  *
95  * XXX: In theory we should only fire up the timer when there is really
96  * activity. Unfortunately we cannot always start timers. We really
97  * don't want to process kernel messages synchronously, because it
98  * really slows down the system.
99  */
100 #define	VT_TIMERFREQ	25
101 
102 /* Bell pitch/duration. */
103 #define VT_BELLDURATION	((5 * hz + 99) / 100)
104 #define VT_BELLPITCH	800
105 
106 #define	VT_LOCK(vd)	mtx_lock(&(vd)->vd_lock)
107 #define	VT_UNLOCK(vd)	mtx_unlock(&(vd)->vd_lock)
108 
109 #define	VT_UNIT(vw)	((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
110 			(vw)->vw_number)
111 
112 /* XXX while syscons is here. */
113 int sc_txtmouse_no_retrace_wait;
114 
115 static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters");
116 VT_SYSCTL_INT(enable_altgr, 0, "Enable AltGr key (Do not assume R.Alt as Alt)");
117 VT_SYSCTL_INT(debug, 0, "Newcons debug level");
118 VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
119 VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend");
120 
121 static unsigned int vt_unit = 0;
122 static MALLOC_DEFINE(M_VT, "vt", "vt device");
123 struct vt_device *main_vd = NULL;
124 
125 /* Boot logo. */
126 extern unsigned int vt_logo_width;
127 extern unsigned int vt_logo_height;
128 extern unsigned int vt_logo_depth;
129 extern unsigned char vt_logo_image[];
130 
131 /* Font. */
132 extern struct vt_font vt_font_default;
133 #ifndef SC_NO_CUTPASTE
134 extern struct mouse_cursor vt_default_mouse_pointer;
135 #endif
136 
137 static int signal_vt_rel(struct vt_window *);
138 static int signal_vt_acq(struct vt_window *);
139 static int finish_vt_rel(struct vt_window *, int, int *);
140 static int finish_vt_acq(struct vt_window *);
141 static int vt_window_switch(struct vt_window *);
142 static int vt_late_window_switch(struct vt_window *);
143 static int vt_proc_alive(struct vt_window *);
144 static void vt_resize(struct vt_device *);
145 
146 static void
147 vt_switch_timer(void *arg)
148 {
149 
150 	vt_late_window_switch((struct vt_window *)arg);
151 }
152 
153 static int
154 vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
155 {
156 
157 	DPRINTF(40, "%s\n", __func__);
158 	curvw->vw_switch_to = vw;
159 	/* Set timer to allow switch in case when process hang. */
160 	callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer,
161 	    vt_switch_timer, (void *)vw);
162 	/* Notify process about vt switch attempt. */
163 	DPRINTF(30, "%s: Notify process.\n", __func__);
164 	signal_vt_rel(curvw);
165 
166 	return (0);
167 }
168 
169 static int
170 vt_window_postswitch(struct vt_window *vw)
171 {
172 
173 	signal_vt_acq(vw);
174 	return (0);
175 }
176 
177 /* vt_late_window_switch will done VT switching for regular case. */
178 static int
179 vt_late_window_switch(struct vt_window *vw)
180 {
181 	int ret;
182 
183 	callout_stop(&vw->vw_proc_dead_timer);
184 
185 	ret = vt_window_switch(vw);
186 	if (ret)
187 		return (ret);
188 
189 	/* Notify owner process about terminal availability. */
190 	if (vw->vw_smode.mode == VT_PROCESS) {
191 		ret = vt_window_postswitch(vw);
192 	}
193 	return (ret);
194 }
195 
196 /* Switch window. */
197 static int
198 vt_proc_window_switch(struct vt_window *vw)
199 {
200 	struct vt_window *curvw;
201 	struct vt_device *vd;
202 	int ret;
203 
204 	if (vw->vw_flags & VWF_VTYLOCK)
205 		return (EBUSY);
206 
207 	vd = vw->vw_device;
208 	curvw = vd->vd_curwindow;
209 
210 	/* Ask current process permitions to switch away. */
211 	if (curvw->vw_smode.mode == VT_PROCESS) {
212 		DPRINTF(30, "%s: VT_PROCESS ", __func__);
213 		if (vt_proc_alive(curvw) == FALSE) {
214 			DPRINTF(30, "Dead. Cleaning.");
215 			/* Dead */
216 		} else {
217 			DPRINTF(30, "%s: Signaling process.\n", __func__);
218 			/* Alive, try to ask him. */
219 			ret = vt_window_preswitch(vw, curvw);
220 			/* Wait for process answer or timeout. */
221 			return (ret);
222 		}
223 		DPRINTF(30, "\n");
224 	}
225 
226 	ret = vt_late_window_switch(vw);
227 	return (ret);
228 }
229 
230 /* Switch window ignoring process locking. */
231 static int
232 vt_window_switch(struct vt_window *vw)
233 {
234 	struct vt_device *vd = vw->vw_device;
235 	struct vt_window *curvw = vd->vd_curwindow;
236 	keyboard_t *kbd;
237 
238 	VT_LOCK(vd);
239 	if (curvw == vw) {
240 		/* Nothing to do. */
241 		VT_UNLOCK(vd);
242 		return (0);
243 	}
244 	if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
245 		VT_UNLOCK(vd);
246 		return (EINVAL);
247 	}
248 
249 	vd->vd_curwindow = vw;
250 	vd->vd_flags |= VDF_INVALID;
251 	cv_broadcast(&vd->vd_winswitch);
252 	VT_UNLOCK(vd);
253 
254 	if (vd->vd_driver->vd_postswitch)
255 		vd->vd_driver->vd_postswitch(vd);
256 
257 	/* Restore per-window keyboard mode. */
258 	mtx_lock(&Giant);
259 	kbd = kbd_get_keyboard(vd->vd_keyboard);
260 	if (kbd != NULL) {
261 		kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode);
262 	}
263 	mtx_unlock(&Giant);
264 	DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
265 
266 	return (0);
267 }
268 
269 static inline void
270 vt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size)
271 {
272 
273 	size->tp_row = vd->vd_height;
274 	size->tp_col = vd->vd_width;
275 	if (vf != NULL) {
276 		size->tp_row /= vf->vf_height;
277 		size->tp_col /= vf->vf_width;
278 	}
279 }
280 
281 static inline void
282 vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size)
283 {
284 
285 	size->ws_row = size->ws_ypixel = vd->vd_height;
286 	size->ws_col = size->ws_xpixel = vd->vd_width;
287 	if (vf != NULL) {
288 		size->ws_row /= vf->vf_height;
289 		size->ws_col /= vf->vf_width;
290 	}
291 }
292 
293 static void
294 vt_scroll(struct vt_window *vw, int offset, int whence)
295 {
296 	int diff;
297 	term_pos_t size;
298 
299 	if ((vw->vw_flags & VWF_SCROLL) == 0)
300 		return;
301 
302 	vt_termsize(vw->vw_device, vw->vw_font, &size);
303 
304 	diff = vthistory_seek(&vw->vw_buf, offset, whence);
305 	/*
306 	 * Offset changed, please update Nth lines on sceen.
307 	 * +N - Nth lines at top;
308 	 * -N - Nth lines at bottom.
309 	 */
310 
311 	if (diff < -size.tp_row || diff > size.tp_row) {
312 		vw->vw_device->vd_flags |= VDF_INVALID;
313 		return;
314 	}
315 	vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/
316 }
317 
318 static int
319 vt_machine_kbdevent(int c)
320 {
321 
322 	switch (c) {
323 	case SPCLKEY | DBG:
324 		kdb_enter(KDB_WHY_BREAK, "manual escape to debugger");
325 		return (1);
326 	case SPCLKEY | RBT:
327 		/* XXX: Make this configurable! */
328 		shutdown_nice(0);
329 		return (1);
330 	case SPCLKEY | HALT:
331 		shutdown_nice(RB_HALT);
332 		return (1);
333 	case SPCLKEY | PDWN:
334 		shutdown_nice(RB_HALT|RB_POWEROFF);
335 		return (1);
336 	};
337 
338 	return (0);
339 }
340 
341 static void
342 vt_scrollmode_kbdevent(struct vt_window *vw, int c, int console)
343 {
344 	struct vt_device *vd;
345 	term_pos_t size;
346 
347 	vd = vw->vw_device;
348 	/* Only special keys handled in ScrollLock mode */
349 	if ((c & SPCLKEY) == 0)
350 		return;
351 
352 	c &= ~SPCLKEY;
353 
354 	if (console == 0) {
355 		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
356 			vw = vd->vd_windows[c - F_SCR];
357 			if (vw != NULL)
358 				vt_proc_window_switch(vw);
359 			return;
360 		}
361 		VT_LOCK(vd);
362 	}
363 
364 	switch (c) {
365 	case SLK: {
366 		/* Turn scrolling off. */
367 		vt_scroll(vw, 0, VHS_END);
368 		VTBUF_SLCK_DISABLE(&vw->vw_buf);
369 		vw->vw_flags &= ~VWF_SCROLL;
370 		break;
371 	}
372 	case FKEY | F(49): /* Home key. */
373 		vt_scroll(vw, 0, VHS_SET);
374 		break;
375 	case FKEY | F(50): /* Arrow up. */
376 		vt_scroll(vw, -1, VHS_CUR);
377 		break;
378 	case FKEY | F(51): /* Page up. */
379 		vt_termsize(vd, vw->vw_font, &size);
380 		vt_scroll(vw, -size.tp_row, VHS_CUR);
381 		break;
382 	case FKEY | F(57): /* End key. */
383 		vt_scroll(vw, 0, VHS_END);
384 		break;
385 	case FKEY | F(58): /* Arrow down. */
386 		vt_scroll(vw, 1, VHS_CUR);
387 		break;
388 	case FKEY | F(59): /* Page down. */
389 		vt_termsize(vd, vw->vw_font, &size);
390 		vt_scroll(vw, size.tp_row, VHS_CUR);
391 		break;
392 	}
393 
394 	if (console == 0)
395 		VT_UNLOCK(vd);
396 }
397 
398 static int
399 vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
400 {
401 	struct vt_window *vw = vd->vd_curwindow;
402 	int state = 0;
403 
404 #if VT_ALT_TO_ESC_HACK
405 	if (c & RELKEY) {
406 		switch (c & ~RELKEY) {
407 		case (SPCLKEY | RALT):
408 			if (vt_enable_altgr != 0)
409 				break;
410 		case (SPCLKEY | LALT):
411 			vd->vd_kbstate &= ~ALKED;
412 		}
413 		/* Other keys ignored for RELKEY event. */
414 		return (0);
415 	} else {
416 		switch (c & ~RELKEY) {
417 		case (SPCLKEY | RALT):
418 		case (SPCLKEY | LALT):
419 			vd->vd_kbstate |= ALKED;
420 		}
421 	}
422 #else
423 	if (c & RELKEY)
424 		/* Other keys ignored for RELKEY event. */
425 		return (0);
426 #endif
427 
428 	if (vt_machine_kbdevent(c))
429 		return (0);
430 
431 	if (vw->vw_flags & VWF_SCROLL) {
432 		vt_scrollmode_kbdevent(vw, c, 0/* Not a console */);
433 		/* Scroll mode keys handled, nothing to do more. */
434 		return (0);
435 	}
436 
437 	if (c & SPCLKEY) {
438 		c &= ~SPCLKEY;
439 
440 		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
441 			vw = vd->vd_windows[c - F_SCR];
442 			if (vw != NULL)
443 				vt_proc_window_switch(vw);
444 			return (0);
445 		}
446 
447 		switch (c) {
448 		case SLK: {
449 
450 			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
451 			VT_LOCK(vd);
452 			if (state & SLKED) {
453 				/* Turn scrolling on. */
454 				vw->vw_flags |= VWF_SCROLL;
455 				VTBUF_SLCK_ENABLE(&vw->vw_buf);
456 			} else {
457 				/* Turn scrolling off. */
458 				vw->vw_flags &= ~VWF_SCROLL;
459 				VTBUF_SLCK_DISABLE(&vw->vw_buf);
460 				vt_scroll(vw, 0, VHS_END);
461 			}
462 			VT_UNLOCK(vd);
463 			break;
464 		}
465 		case FKEY | F(1):  case FKEY | F(2):  case FKEY | F(3):
466 		case FKEY | F(4):  case FKEY | F(5):  case FKEY | F(6):
467 		case FKEY | F(7):  case FKEY | F(8):  case FKEY | F(9):
468 		case FKEY | F(10): case FKEY | F(11): case FKEY | F(12):
469 			/* F1 through F12 keys. */
470 			terminal_input_special(vw->vw_terminal,
471 			    TKEY_F1 + c - (FKEY | F(1)));
472 			break;
473 		case FKEY | F(49): /* Home key. */
474 			terminal_input_special(vw->vw_terminal, TKEY_HOME);
475 			break;
476 		case FKEY | F(50): /* Arrow up. */
477 			terminal_input_special(vw->vw_terminal, TKEY_UP);
478 			break;
479 		case FKEY | F(51): /* Page up. */
480 			terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP);
481 			break;
482 		case FKEY | F(53): /* Arrow left. */
483 			terminal_input_special(vw->vw_terminal, TKEY_LEFT);
484 			break;
485 		case FKEY | F(55): /* Arrow right. */
486 			terminal_input_special(vw->vw_terminal, TKEY_RIGHT);
487 			break;
488 		case FKEY | F(57): /* End key. */
489 			terminal_input_special(vw->vw_terminal, TKEY_END);
490 			break;
491 		case FKEY | F(58): /* Arrow down. */
492 			terminal_input_special(vw->vw_terminal, TKEY_DOWN);
493 			break;
494 		case FKEY | F(59): /* Page down. */
495 			terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN);
496 			break;
497 		case FKEY | F(60): /* Insert key. */
498 			terminal_input_special(vw->vw_terminal, TKEY_INSERT);
499 			break;
500 		case FKEY | F(61): /* Delete key. */
501 			terminal_input_special(vw->vw_terminal, TKEY_DELETE);
502 			break;
503 		}
504 	} else if (KEYFLAGS(c) == 0) {
505 		/* Don't do UTF-8 conversion when doing raw mode. */
506 		if (vw->vw_kbdmode == K_XLATE) {
507 #if VT_ALT_TO_ESC_HACK
508 			if (vd->vd_kbstate & ALKED) {
509 				/*
510 				 * Prepend ESC sequence if one of ALT keys down.
511 				 */
512 				terminal_input_char(vw->vw_terminal, 0x1b);
513 			}
514 #endif
515 
516 			terminal_input_char(vw->vw_terminal, KEYCHAR(c));
517 		} else
518 			terminal_input_raw(vw->vw_terminal, c);
519 	}
520 	return (0);
521 }
522 
523 static int
524 vt_kbdevent(keyboard_t *kbd, int event, void *arg)
525 {
526 	struct vt_device *vd = arg;
527 	int c;
528 
529 	switch (event) {
530 	case KBDIO_KEYINPUT:
531 		break;
532 	case KBDIO_UNLOADING:
533 		mtx_lock(&Giant);
534 		vd->vd_keyboard = -1;
535 		kbd_release(kbd, (void *)&vd->vd_keyboard);
536 		mtx_unlock(&Giant);
537 		return (0);
538 	default:
539 		return (EINVAL);
540 	}
541 
542 	while ((c = kbdd_read_char(kbd, 0)) != NOKEY)
543 		vt_processkey(kbd, vd, c);
544 
545 	return (0);
546 }
547 
548 static int
549 vt_allocate_keyboard(struct vt_device *vd)
550 {
551 	int		 idx0, idx;
552 	keyboard_t	*k0, *k;
553 	keyboard_info_t	 ki;
554 
555 	idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard,
556 	    vt_kbdevent, vd);
557 	/* XXX: kb_token lost */
558 	vd->vd_keyboard = idx0;
559 	if (idx0 != -1) {
560 		DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
561 		k0 = kbd_get_keyboard(idx0);
562 
563 		for (idx = kbd_find_keyboard2("*", -1, 0);
564 		     idx != -1;
565 		     idx = kbd_find_keyboard2("*", -1, idx + 1)) {
566 			k = kbd_get_keyboard(idx);
567 
568 			if (idx == idx0 || KBD_IS_BUSY(k))
569 				continue;
570 
571 			bzero(&ki, sizeof(ki));
572 			strcpy(ki.kb_name, k->kb_name);
573 			ki.kb_unit = k->kb_unit;
574 
575 			kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
576 		}
577 	} else {
578 		DPRINTF(20, "%s: no kbdmux allocated\n", __func__);
579 		idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard,
580 		    vt_kbdevent, vd);
581 	}
582 	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
583 
584 	return (idx0);
585 }
586 
587 static void
588 vtterm_bell(struct terminal *tm)
589 {
590 
591 	sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION);
592 }
593 
594 static void
595 vtterm_cursor(struct terminal *tm, const term_pos_t *p)
596 {
597 	struct vt_window *vw = tm->tm_softc;
598 
599 	vtbuf_cursor_position(&vw->vw_buf, p);
600 }
601 
602 static void
603 vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c)
604 {
605 	struct vt_window *vw = tm->tm_softc;
606 
607 	vtbuf_putchar(&vw->vw_buf, p, c);
608 }
609 
610 static void
611 vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c)
612 {
613 	struct vt_window *vw = tm->tm_softc;
614 
615 	vtbuf_fill_locked(&vw->vw_buf, r, c);
616 }
617 
618 static void
619 vtterm_copy(struct terminal *tm, const term_rect_t *r,
620     const term_pos_t *p)
621 {
622 	struct vt_window *vw = tm->tm_softc;
623 
624 	vtbuf_copy(&vw->vw_buf, r, p);
625 }
626 
627 static void
628 vtterm_param(struct terminal *tm, int cmd, unsigned int arg)
629 {
630 	struct vt_window *vw = tm->tm_softc;
631 
632 	switch (cmd) {
633 	case TP_SHOWCURSOR:
634 		vtbuf_cursor_visibility(&vw->vw_buf, arg);
635 		break;
636 	}
637 }
638 
639 static inline void
640 vt_determine_colors(term_char_t c, int cursor,
641     term_color_t *fg, term_color_t *bg)
642 {
643 
644 	*fg = TCHAR_FGCOLOR(c);
645 	if (TCHAR_FORMAT(c) & TF_BOLD)
646 		*fg = TCOLOR_LIGHT(*fg);
647 	*bg = TCHAR_BGCOLOR(c);
648 
649 	if (TCHAR_FORMAT(c) & TF_REVERSE) {
650 		term_color_t tmp;
651 
652 		tmp = *fg;
653 		*fg = *bg;
654 		*bg = tmp;
655 	}
656 
657 	if (cursor) {
658 		*fg = *bg;
659 		*bg = TC_WHITE;
660 	}
661 }
662 
663 static void
664 vt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c,
665     int iscursor, unsigned int row, unsigned int col)
666 {
667 	term_color_t fg, bg;
668 
669 	vt_determine_colors(c, iscursor, &fg, &bg);
670 
671 	if (vf != NULL) {
672 		const uint8_t *src;
673 		vt_axis_t top, left;
674 
675 		src = vtfont_lookup(vf, c);
676 
677 		/*
678 		 * Align the terminal to the centre of the screen.
679 		 * Fonts may not always be able to fill the entire
680 		 * screen.
681 		 */
682 		top = row * vf->vf_height + vd->vd_offset.tp_row;
683 		left = col * vf->vf_width + vd->vd_offset.tp_col;
684 
685 		vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left,
686 		    vf->vf_width, vf->vf_height, fg, bg);
687 	} else {
688 		vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c),
689 		    row, col, fg, bg);
690 	}
691 }
692 
693 static void
694 vt_flush(struct vt_device *vd)
695 {
696 	struct vt_window *vw = vd->vd_curwindow;
697 	struct vt_font *vf = vw->vw_font;
698 	struct vt_bufmask tmask;
699 	unsigned int row, col;
700 	term_rect_t tarea;
701 	term_pos_t size;
702 	term_char_t *r;
703 #ifndef SC_NO_CUTPASTE
704 	struct mouse_cursor *m;
705 	int bpl, h, w;
706 #endif
707 
708 	if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
709 		return;
710 
711 	vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
712 	vt_termsize(vd, vf, &size);
713 
714 	/* Force a full redraw when the screen contents are invalid. */
715 	if (vd->vd_flags & VDF_INVALID) {
716 		tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0;
717 		tarea.tr_end = size;
718 		tmask.vbm_row = tmask.vbm_col = VBM_DIRTY;
719 
720 		vd->vd_flags &= ~VDF_INVALID;
721 	}
722 
723 #ifndef SC_NO_CUTPASTE
724 	if ((vw->vw_flags & VWF_MOUSE_HIDE) == 0) {
725 		/* Mark last mouse position as dirty to erase. */
726 		vtbuf_mouse_cursor_position(&vw->vw_buf, vd->vd_mdirtyx,
727 		    vd->vd_mdirtyy);
728 	}
729 #endif
730 
731 	for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) {
732 		if (!VTBUF_DIRTYROW(&tmask, row))
733 			continue;
734 		r = VTBUF_GET_ROW(&vw->vw_buf, row);
735 		for (col = tarea.tr_begin.tp_col;
736 		    col < tarea.tr_end.tp_col; col++) {
737 			if (!VTBUF_DIRTYCOL(&tmask, col))
738 				continue;
739 
740 			vt_bitblt_char(vd, vf, r[col],
741 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col);
742 		}
743 	}
744 
745 #ifndef SC_NO_CUTPASTE
746 	/* Mouse disabled. */
747 	if (vw->vw_flags & VWF_MOUSE_HIDE)
748 		return;
749 
750 	/* No mouse for DDB. */
751 	if (kdb_active || panicstr != NULL)
752 		return;
753 
754 	if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) ==
755 	    VDF_MOUSECURSOR) {
756 		m = &vt_default_mouse_pointer;
757 		bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */
758 		w = m->w;
759 		h = m->h;
760 
761 		if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width))
762 			w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1;
763 		if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height))
764 			h = (size.tp_row * vf->vf_height) - vd->vd_my - 1;
765 
766 		vd->vd_driver->vd_bitbltchr(vd, m->map, m->mask, bpl,
767 		    vd->vd_offset.tp_row + vd->vd_my,
768 		    vd->vd_offset.tp_col + vd->vd_mx,
769 		    w, h, TC_WHITE, TC_BLACK);
770 		/* Save point of last mouse cursor to erase it later. */
771 		vd->vd_mdirtyx = vd->vd_mx / vf->vf_width;
772 		vd->vd_mdirtyy = vd->vd_my / vf->vf_height;
773 	}
774 #endif
775 }
776 
777 static void
778 vt_timer(void *arg)
779 {
780 	struct vt_device *vd;
781 
782 	vd = arg;
783 	/* Update screen if required. */
784 	vt_flush(vd);
785 	/* Schedule for next update. */
786 	callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
787 }
788 
789 static void
790 vtterm_done(struct terminal *tm)
791 {
792 	struct vt_window *vw = tm->tm_softc;
793 	struct vt_device *vd = vw->vw_device;
794 
795 	if (kdb_active || panicstr != NULL) {
796 		/* Switch to the debugger. */
797 		if (vd->vd_curwindow != vw) {
798 			vd->vd_curwindow = vw;
799 			vd->vd_flags |= VDF_INVALID;
800 			if (vd->vd_driver->vd_postswitch)
801 				vd->vd_driver->vd_postswitch(vd);
802 		}
803 		vd->vd_flags &= ~VDF_SPLASH;
804 		vt_flush(vd);
805 	} else if (!(vd->vd_flags & VDF_ASYNC)) {
806 		vt_flush(vd);
807 	}
808 }
809 
810 #ifdef DEV_SPLASH
811 static void
812 vtterm_splash(struct vt_device *vd)
813 {
814 	vt_axis_t top, left;
815 
816 	/* Display a nice boot splash. */
817 	if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) {
818 
819 		top = (vd->vd_height - vt_logo_height) / 2;
820 		left = (vd->vd_width - vt_logo_width) / 2;
821 		switch (vt_logo_depth) {
822 		case 1:
823 			/* XXX: Unhardcode colors! */
824 			vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0,
825 			    top, left, vt_logo_width, vt_logo_height, 0xf, 0x0);
826 		}
827 		vd->vd_flags |= VDF_SPLASH;
828 	}
829 }
830 #endif
831 
832 static void
833 vtterm_cnprobe(struct terminal *tm, struct consdev *cp)
834 {
835 	struct vt_window *vw = tm->tm_softc;
836 	struct vt_device *vd = vw->vw_device;
837 	struct winsize wsz;
838 
839 	if (vd->vd_flags & VDF_INITIALIZED)
840 		/* Initialization already done. */
841 		return;
842 
843 	cp->cn_pri = vd->vd_driver->vd_init(vd);
844 	if (cp->cn_pri == CN_DEAD) {
845 		vd->vd_flags |= VDF_DEAD;
846 		return;
847 	}
848 
849 	/* Initialize any early-boot keyboard drivers */
850 	kbd_configure(KB_CONF_PROBE_ONLY);
851 
852 	vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1);
853 	vd->vd_windows[VT_CONSWINDOW] = vw;
854 	sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw));
855 
856 	if (!(vd->vd_flags & VDF_TEXTMODE))
857 		vw->vw_font = vtfont_ref(&vt_font_default);
858 
859 	vtbuf_init_early(&vw->vw_buf);
860 	vt_winsize(vd, vw->vw_font, &wsz);
861 	terminal_set_winsize(tm, &wsz);
862 
863 #ifdef DEV_SPLASH
864 	vtterm_splash(vd);
865 #endif
866 
867 	vd->vd_flags |= VDF_INITIALIZED;
868 	main_vd = vd;
869 }
870 
871 static int
872 vtterm_cngetc(struct terminal *tm)
873 {
874 	struct vt_window *vw = tm->tm_softc;
875 	struct vt_device *vd = vw->vw_device;
876 	keyboard_t *kbd;
877 	int state;
878 	u_int c;
879 
880 	if (vw->vw_kbdsq && *vw->vw_kbdsq)
881 		return (*vw->vw_kbdsq++);
882 
883 	state = 0;
884 	/* Make sure the splash screen is not there. */
885 	if (vd->vd_flags & VDF_SPLASH) {
886 		/* Remove splash */
887 		vd->vd_flags &= ~VDF_SPLASH;
888 		/* Mark screen as invalid to force update */
889 		vd->vd_flags |= VDF_INVALID;
890 		vt_flush(vd);
891 	}
892 
893 	/* Stripped down keyboard handler. */
894 	kbd = kbd_get_keyboard(vd->vd_keyboard);
895 	if (kbd == NULL)
896 		return (-1);
897 
898 	/* Force keyboard input mode to K_XLATE */
899 	c = K_XLATE;
900 	kbdd_ioctl(kbd, KDSKBMODE, (void *)&c);
901 
902 	/* Switch the keyboard to polling to make it work here. */
903 	kbdd_poll(kbd, TRUE);
904 	c = kbdd_read_char(kbd, 0);
905 	kbdd_poll(kbd, FALSE);
906 	if (c & RELKEY)
907 		return (-1);
908 
909 	if (vw->vw_flags & VWF_SCROLL) {
910 		vt_scrollmode_kbdevent(vw, c, 1/* Console mode */);
911 		vt_flush(vd);
912 		return (-1);
913 	}
914 
915 	/* Stripped down handling of vt_kbdevent(), without locking, etc. */
916 	if (c & SPCLKEY) {
917 		switch (c) {
918 		case SPCLKEY | SLK:
919 			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
920 			if (state & SLKED) {
921 				/* Turn scrolling on. */
922 				vw->vw_flags |= VWF_SCROLL;
923 				VTBUF_SLCK_ENABLE(&vw->vw_buf);
924 			} else {
925 				/* Turn scrolling off. */
926 				vt_scroll(vw, 0, VHS_END);
927 				vw->vw_flags &= ~VWF_SCROLL;
928 				VTBUF_SLCK_DISABLE(&vw->vw_buf);
929 			}
930 			break;
931 		/* XXX: KDB can handle history. */
932 		case SPCLKEY | FKEY | F(50): /* Arrow up. */
933 			vw->vw_kbdsq = "\x1b[A";
934 			break;
935 		case SPCLKEY | FKEY | F(58): /* Arrow down. */
936 			vw->vw_kbdsq = "\x1b[B";
937 			break;
938 		case SPCLKEY | FKEY | F(55): /* Arrow right. */
939 			vw->vw_kbdsq = "\x1b[C";
940 			break;
941 		case SPCLKEY | FKEY | F(53): /* Arrow left. */
942 			vw->vw_kbdsq = "\x1b[D";
943 			break;
944 		}
945 
946 		/* Force refresh to make scrollback work. */
947 		vt_flush(vd);
948 	} else if (KEYFLAGS(c) == 0) {
949 		return (KEYCHAR(c));
950 	}
951 
952 	if (vw->vw_kbdsq && *vw->vw_kbdsq)
953 		return (*vw->vw_kbdsq++);
954 
955 	return (-1);
956 }
957 
958 static void
959 vtterm_opened(struct terminal *tm, int opened)
960 {
961 	struct vt_window *vw = tm->tm_softc;
962 	struct vt_device *vd = vw->vw_device;
963 
964 	VT_LOCK(vd);
965 	vd->vd_flags &= ~VDF_SPLASH;
966 	if (opened)
967 		vw->vw_flags |= VWF_OPENED;
968 	else {
969 		vw->vw_flags &= ~VWF_OPENED;
970 		/* TODO: finish ACQ/REL */
971 	}
972 	VT_UNLOCK(vd);
973 }
974 
975 static int
976 vt_change_font(struct vt_window *vw, struct vt_font *vf)
977 {
978 	struct vt_device *vd = vw->vw_device;
979 	struct terminal *tm = vw->vw_terminal;
980 	term_pos_t size;
981 	struct winsize wsz;
982 
983 	/*
984 	 * Changing fonts.
985 	 *
986 	 * Changing fonts is a little tricky.  We must prevent
987 	 * simultaneous access to the device, so we must stop
988 	 * the display timer and the terminal from accessing.
989 	 * We need to switch fonts and grow our screen buffer.
990 	 *
991 	 * XXX: Right now the code uses terminal_mute() to
992 	 * prevent data from reaching the console driver while
993 	 * resizing the screen buffer.  This isn't elegant...
994 	 */
995 
996 	VT_LOCK(vd);
997 	if (vw->vw_flags & VWF_BUSY) {
998 		/* Another process is changing the font. */
999 		VT_UNLOCK(vd);
1000 		return (EBUSY);
1001 	}
1002 	if (vw->vw_font == NULL) {
1003 		/* Our device doesn't need fonts. */
1004 		VT_UNLOCK(vd);
1005 		return (ENOTTY);
1006 	}
1007 	vw->vw_flags |= VWF_BUSY;
1008 	VT_UNLOCK(vd);
1009 
1010 	vt_termsize(vd, vf, &size);
1011 	vt_winsize(vd, vf, &wsz);
1012 	/* Save offset to font aligned area. */
1013 	vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2;
1014 	vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2;
1015 
1016 	/* Grow the screen buffer and terminal. */
1017 	terminal_mute(tm, 1);
1018 	vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
1019 	terminal_set_winsize_blank(tm, &wsz, 0);
1020 	terminal_mute(tm, 0);
1021 
1022 	/* Actually apply the font to the current window. */
1023 	VT_LOCK(vd);
1024 	vtfont_unref(vw->vw_font);
1025 	vw->vw_font = vtfont_ref(vf);
1026 
1027 	/* Force a full redraw the next timer tick. */
1028 	if (vd->vd_curwindow == vw)
1029 		vd->vd_flags |= VDF_INVALID;
1030 	vw->vw_flags &= ~VWF_BUSY;
1031 	VT_UNLOCK(vd);
1032 	return (0);
1033 }
1034 
1035 static int
1036 vt_proc_alive(struct vt_window *vw)
1037 {
1038 	struct proc *p;
1039 
1040 	if (vw->vw_smode.mode != VT_PROCESS)
1041 		return (FALSE);
1042 
1043 	if (vw->vw_proc) {
1044 		if ((p = pfind(vw->vw_pid)) != NULL)
1045 			PROC_UNLOCK(p);
1046 		if (vw->vw_proc == p)
1047 			return (TRUE);
1048 		vw->vw_proc = NULL;
1049 		vw->vw_smode.mode = VT_AUTO;
1050 		DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid);
1051 		vw->vw_pid = 0;
1052 	}
1053 	return (FALSE);
1054 }
1055 
1056 static int
1057 signal_vt_rel(struct vt_window *vw)
1058 {
1059 
1060 	if (vw->vw_smode.mode != VT_PROCESS)
1061 		return (FALSE);
1062 	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
1063 		vw->vw_proc = NULL;
1064 		vw->vw_pid = 0;
1065 		return (TRUE);
1066 	}
1067 	vw->vw_flags |= VWF_SWWAIT_REL;
1068 	PROC_LOCK(vw->vw_proc);
1069 	kern_psignal(vw->vw_proc, vw->vw_smode.relsig);
1070 	PROC_UNLOCK(vw->vw_proc);
1071 	DPRINTF(1, "sending relsig to %d\n", vw->vw_pid);
1072 	return (TRUE);
1073 }
1074 
1075 static int
1076 signal_vt_acq(struct vt_window *vw)
1077 {
1078 
1079 	if (vw->vw_smode.mode != VT_PROCESS)
1080 		return (FALSE);
1081 	if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1082 		cnavailable(vw->vw_terminal->consdev, FALSE);
1083 	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
1084 		vw->vw_proc = NULL;
1085 		vw->vw_pid = 0;
1086 		return (TRUE);
1087 	}
1088 	vw->vw_flags |= VWF_SWWAIT_ACQ;
1089 	PROC_LOCK(vw->vw_proc);
1090 	kern_psignal(vw->vw_proc, vw->vw_smode.acqsig);
1091 	PROC_UNLOCK(vw->vw_proc);
1092 	DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid);
1093 	return (TRUE);
1094 }
1095 
1096 static int
1097 finish_vt_rel(struct vt_window *vw, int release, int *s)
1098 {
1099 
1100 	if (vw->vw_flags & VWF_SWWAIT_REL) {
1101 		vw->vw_flags &= ~VWF_SWWAIT_REL;
1102 		if (release) {
1103 			callout_drain(&vw->vw_proc_dead_timer);
1104 			vt_late_window_switch(vw->vw_switch_to);
1105 		}
1106 		return (0);
1107 	}
1108 	return (EINVAL);
1109 }
1110 
1111 static int
1112 finish_vt_acq(struct vt_window *vw)
1113 {
1114 
1115 	if (vw->vw_flags & VWF_SWWAIT_ACQ) {
1116 		vw->vw_flags &= ~VWF_SWWAIT_ACQ;
1117 		return (0);
1118 	}
1119 	return (EINVAL);
1120 }
1121 
1122 #ifndef SC_NO_CUTPASTE
1123 void
1124 vt_mouse_event(int type, int x, int y, int event, int cnt)
1125 {
1126 	struct vt_device *vd;
1127 	struct vt_window *vw;
1128 	struct vt_font *vf;
1129 	term_pos_t size;
1130 	term_char_t *buf;
1131 	int i, len, mark;
1132 
1133 	vd = main_vd;
1134 	vw = vd->vd_curwindow;
1135 	vf = vw->vw_font;
1136 	mark = 0;
1137 
1138 	if (vw->vw_flags & VWF_MOUSE_HIDE)
1139 		return; /* Mouse disabled. */
1140 
1141 	if (vf == NULL)	/* Text mode. */
1142 		return;
1143 
1144 	/*
1145 	 * TODO: add flag about pointer position changed, to not redraw chars
1146 	 * under mouse pointer when nothing changed.
1147 	 */
1148 
1149 	switch (type) {
1150 	case MOUSE_ACTION:
1151 	case MOUSE_MOTION_EVENT:
1152 		/* Movement */
1153 		x += vd->vd_mx;
1154 		y += vd->vd_my;
1155 
1156 		vt_termsize(vd, vf, &size);
1157 
1158 		/* Apply limits. */
1159 		x = MAX(x, 0);
1160 		y = MAX(y, 0);
1161 		x = MIN(x, (size.tp_col * vf->vf_width) - 1);
1162 		y = MIN(y, (size.tp_row * vf->vf_height) - 1);
1163 
1164 		vd->vd_mx = x;
1165 		vd->vd_my = y;
1166 		if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) &&
1167 		    (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE,
1168 			vd->vd_mx / vf->vf_width,
1169 			vd->vd_my / vf->vf_height) == 1)) {
1170 
1171 			/*
1172 			 * We have something marked to copy, so update pointer
1173 			 * to window with selection.
1174 			 */
1175 			vd->vd_markedwin = vw;
1176 		}
1177 		return; /* Done */
1178 	case MOUSE_BUTTON_EVENT:
1179 		/* Buttons */
1180 		break;
1181 	default:
1182 		return; /* Done */
1183 	}
1184 
1185 	switch (event) {
1186 	case MOUSE_BUTTON1DOWN:
1187 		switch (cnt % 4) {
1188 		case 0:	/* up */
1189 			mark = VTB_MARK_END;
1190 			break;
1191 		case 1: /* single click: start cut operation */
1192 			mark = VTB_MARK_START;
1193 			break;
1194 		case 2:	/* double click: cut a word */
1195 			mark = VTB_MARK_WORD;
1196 			break;
1197 		case 3:	/* triple click: cut a line */
1198 			mark = VTB_MARK_ROW;
1199 			break;
1200 		}
1201 		break;
1202 	case VT_MOUSE_PASTEBUTTON:
1203 		switch (cnt) {
1204 		case 0:	/* up */
1205 			break;
1206 		default:
1207 			if (vd->vd_markedwin == NULL)
1208 				return;
1209 			/* Get current selecton size in bytes. */
1210 			len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf);
1211 			if (len <= 0)
1212 				return;
1213 
1214 			buf = malloc(len, M_VT, M_WAITOK | M_ZERO);
1215 			/* Request cupy/paste buffer data, no more than `len' */
1216 			vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf,
1217 			    len);
1218 
1219 			len /= sizeof(term_char_t);
1220 			for (i = 0; i < len; i++ ) {
1221 				if (buf[i] == '\0')
1222 					continue;
1223 				terminal_input_char(vw->vw_terminal, buf[i]);
1224 			}
1225 
1226 			/* Done, so cleanup. */
1227 			free(buf, M_VT);
1228 			break;
1229 		}
1230 		return; /* Done */
1231 	case VT_MOUSE_EXTENDBUTTON:
1232 		switch (cnt) {
1233 		case 0:	/* up */
1234 			if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN))
1235 				mark = VTB_MARK_EXTEND;
1236 			else
1237 				mark = 0;
1238 			break;
1239 		default:
1240 			mark = VTB_MARK_EXTEND;
1241 			break;
1242 		}
1243 		break;
1244 	default:
1245 		return; /* Done */
1246 	}
1247 
1248 	/* Save buttons state. */
1249 	if (cnt > 0)
1250 		vd->vd_mstate |= event;
1251 	else
1252 		vd->vd_mstate &= ~event;
1253 
1254 	if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width,
1255 	    vd->vd_my / vf->vf_height) == 1) {
1256 		/*
1257 		 * We have something marked to copy, so update pointer to
1258 		 * window with selection.
1259 		 */
1260 		vd->vd_markedwin = vw;
1261 	}
1262 }
1263 
1264 void
1265 vt_mouse_state(int show)
1266 {
1267 	struct vt_device *vd;
1268 	struct vt_window *vw;
1269 
1270 	vd = main_vd;
1271 	vw = vd->vd_curwindow;
1272 
1273 	switch (show) {
1274 	case VT_MOUSE_HIDE:
1275 		vw->vw_flags |= VWF_MOUSE_HIDE;
1276 		break;
1277 	case VT_MOUSE_SHOW:
1278 		vw->vw_flags &= ~VWF_MOUSE_HIDE;
1279 		break;
1280 	}
1281 }
1282 #endif
1283 
1284 static int
1285 vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
1286     struct thread *td)
1287 {
1288 	struct vt_window *vw = tm->tm_softc;
1289 	struct vt_device *vd = vw->vw_device;
1290 	keyboard_t *kbd;
1291 	int error, i, s;
1292 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
1293     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
1294 	int ival;
1295 
1296 	switch (cmd) {
1297 	case _IO('v', 4):
1298 		cmd = VT_RELDISP;
1299 		break;
1300 	case _IO('v', 5):
1301 		cmd = VT_ACTIVATE;
1302 		break;
1303 	case _IO('v', 6):
1304 		cmd = VT_WAITACTIVE;
1305 		break;
1306 	case _IO('K', 20):
1307 		cmd = KDSKBSTATE;
1308 		break;
1309 	case _IO('K', 67):
1310 		cmd = KDSETRAD;
1311 		break;
1312 	case _IO('K', 7):
1313 		cmd = KDSKBMODE;
1314 		break;
1315 	case _IO('K', 8):
1316 		cmd = KDMKTONE;
1317 		break;
1318 	case _IO('K', 63):
1319 		cmd = KIOCSOUND;
1320 		break;
1321 	case _IO('K', 66):
1322 		cmd = KDSETLED;
1323 		break;
1324 	case _IO('c', 110):
1325 		cmd = CONS_SETKBD;
1326 		break;
1327 	default:
1328 		goto skip_thunk;
1329 	}
1330 	ival = IOCPARM_IVAL(data);
1331 	data = (caddr_t)&ival;
1332 skip_thunk:
1333 #endif
1334 
1335 	switch (cmd) {
1336 	case KDSETRAD:		/* set keyboard repeat & delay rates (old) */
1337 		if (*(int *)data & ~0x7f)
1338 			return (EINVAL);
1339 	case GIO_KEYMAP:
1340 	case PIO_KEYMAP:
1341 	case GIO_DEADKEYMAP:
1342 	case PIO_DEADKEYMAP:
1343 	case GETFKEY:
1344 	case SETFKEY:
1345 	case KDGKBINFO:
1346 	case KDGKBTYPE:
1347 	case KDSKBSTATE:	/* set keyboard state (locks) */
1348 	case KDGKBSTATE:	/* get keyboard state (locks) */
1349 	case KDGETREPEAT:	/* get keyboard repeat & delay rates */
1350 	case KDSETREPEAT:	/* set keyboard repeat & delay rates (new) */
1351 	case KDSETLED:		/* set keyboard LED status */
1352 	case KDGETLED:		/* get keyboard LED status */
1353 	case KBADDKBD:		/* add/remove keyboard to/from mux */
1354 	case KBRELKBD: {
1355 		error = 0;
1356 
1357 		mtx_lock(&Giant);
1358 		kbd = kbd_get_keyboard(vd->vd_keyboard);
1359 		if (kbd != NULL)
1360 			error = kbdd_ioctl(kbd, cmd, data);
1361 		mtx_unlock(&Giant);
1362 		if (error == ENOIOCTL) {
1363 			if (cmd == KDGKBTYPE) {
1364 				/* always return something? XXX */
1365 				*(int *)data = 0;
1366 			} else {
1367 				return (ENODEV);
1368 			}
1369 		}
1370 		return (error);
1371 	}
1372 	case KDGKBMODE: {
1373 		int mode = -1;
1374 
1375 		mtx_lock(&Giant);
1376 		kbd = kbd_get_keyboard(vd->vd_keyboard);
1377 		if (kbd != NULL) {
1378 			kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode);
1379 		}
1380 		mtx_unlock(&Giant);
1381 		DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode);
1382 		*(int *)data = mode;
1383 		return (0);
1384 	}
1385 	case KDSKBMODE: {
1386 		int mode;
1387 
1388 		mode = *(int *)data;
1389 		switch (mode) {
1390 		case K_XLATE:
1391 		case K_RAW:
1392 		case K_CODE:
1393 			vw->vw_kbdmode = mode;
1394 			if (vw == vd->vd_curwindow) {
1395 				keyboard_t *kbd;
1396 				error = 0;
1397 
1398 				mtx_lock(&Giant);
1399 				kbd = kbd_get_keyboard(vd->vd_keyboard);
1400 				if (kbd != NULL) {
1401 					error = kbdd_ioctl(kbd, KDSKBMODE,
1402 					    (void *)&mode);
1403 				}
1404 				mtx_unlock(&Giant);
1405 			}
1406 			return (0);
1407 		default:
1408 			return (EINVAL);
1409 		}
1410 	}
1411 	case CONS_BLANKTIME:
1412 		/* XXX */
1413 		return (0);
1414 	case CONS_GET:
1415 		/* XXX */
1416 		*(int *)data = M_CG640x480;
1417 		return (0);
1418 	case CONS_GETINFO: {
1419 		vid_info_t *vi = (vid_info_t *)data;
1420 
1421 		vi->m_num = vd->vd_curwindow->vw_number + 1;
1422 		/* XXX: other fields! */
1423 		return (0);
1424 	}
1425 	case CONS_GETVERS:
1426 		*(int *)data = 0x200;
1427 		return (0);
1428 	case CONS_MODEINFO:
1429 		/* XXX */
1430 		return (0);
1431 	case CONS_MOUSECTL: {
1432 		mouse_info_t *mouse = (mouse_info_t*)data;
1433 
1434 		/*
1435 		 * This has no effect on vt(4).  We don't draw any mouse
1436 		 * cursor.  Just ignore MOUSE_HIDE and MOUSE_SHOW to
1437 		 * prevent excessive errors.  All the other commands
1438 		 * should not be applied to individual TTYs, but only to
1439 		 * consolectl.
1440 		 */
1441 		switch (mouse->operation) {
1442 		case MOUSE_HIDE:
1443 			vd->vd_flags &= ~VDF_MOUSECURSOR;
1444 			return (0);
1445 		case MOUSE_SHOW:
1446 			vd->vd_mx = vd->vd_width / 2;
1447 			vd->vd_my = vd->vd_height / 2;
1448 			vd->vd_flags |= VDF_MOUSECURSOR;
1449 			return (0);
1450 		default:
1451 			return (EINVAL);
1452 		}
1453 	}
1454 	case PIO_VFONT: {
1455 		struct vt_font *vf;
1456 
1457 		error = vtfont_load((void *)data, &vf);
1458 		if (error != 0)
1459 			return (error);
1460 
1461 		error = vt_change_font(vw, vf);
1462 		vtfont_unref(vf);
1463 		return (error);
1464 	}
1465 	case GIO_SCRNMAP: {
1466 		scrmap_t *sm = (scrmap_t *)data;
1467 		int i;
1468 
1469 		/* We don't have screen maps, so return a handcrafted one. */
1470 		for (i = 0; i < 256; i++)
1471 			sm->scrmap[i] = i;
1472 		return (0);
1473 	}
1474 	case KDSETMODE:
1475 		/* XXX */
1476 		return (0);
1477 	case KDENABIO:      	/* allow io operations */
1478 		error = priv_check(td, PRIV_IO);
1479 		if (error != 0)
1480 			return (error);
1481 		error = securelevel_gt(td->td_ucred, 0);
1482 		if (error != 0)
1483 			return (error);
1484 #if defined(__i386__)
1485 		td->td_frame->tf_eflags |= PSL_IOPL;
1486 #elif defined(__amd64__)
1487 		td->td_frame->tf_rflags |= PSL_IOPL;
1488 #endif
1489 		return (0);
1490 	case KDDISABIO:     	/* disallow io operations (default) */
1491 #if defined(__i386__)
1492 		td->td_frame->tf_eflags &= ~PSL_IOPL;
1493 #elif defined(__amd64__)
1494 		td->td_frame->tf_rflags &= ~PSL_IOPL;
1495 #endif
1496 		return (0);
1497 	case KDMKTONE:      	/* sound the bell */
1498 		/* TODO */
1499 		return (0);
1500 	case KIOCSOUND:     	/* make tone (*data) hz */
1501 		/* TODO */
1502 		return (0);
1503 	case CONS_SETKBD: 		/* set the new keyboard */
1504 		mtx_lock(&Giant);
1505 		error = 0;
1506 		if (vd->vd_keyboard != *(int *)data) {
1507 			kbd = kbd_get_keyboard(*(int *)data);
1508 			if (kbd == NULL) {
1509 				mtx_unlock(&Giant);
1510 				return (EINVAL);
1511 			}
1512 			i = kbd_allocate(kbd->kb_name, kbd->kb_unit,
1513 			    (void *)&vd->vd_keyboard, vt_kbdevent, vd);
1514 			if (i >= 0) {
1515 				if (vd->vd_keyboard != -1) {
1516 					kbd_release(kbd,
1517 					    (void *)&vd->vd_keyboard);
1518 				}
1519 				kbd = kbd_get_keyboard(i);
1520 				vd->vd_keyboard = i;
1521 
1522 				(void)kbdd_ioctl(kbd, KDSKBMODE,
1523 				    (caddr_t)&vd->vd_curwindow->vw_kbdmode);
1524 			} else {
1525 				error = EPERM;	/* XXX */
1526 			}
1527 		}
1528 		mtx_unlock(&Giant);
1529 		return (error);
1530 	case CONS_RELKBD: 		/* release the current keyboard */
1531 		mtx_lock(&Giant);
1532 		error = 0;
1533 		if (vd->vd_keyboard != -1) {
1534 			kbd = kbd_get_keyboard(vd->vd_keyboard);
1535 			if (kbd == NULL) {
1536 				mtx_unlock(&Giant);
1537 				return (EINVAL);
1538 			}
1539 			error = kbd_release(kbd, (void *)&vd->vd_keyboard);
1540 			if (error == 0) {
1541 				vd->vd_keyboard = -1;
1542 			}
1543 		}
1544 		mtx_unlock(&Giant);
1545 		return (error);
1546 	case VT_ACTIVATE: {
1547 		int win;
1548 		win = *(int *)data - 1;
1549 		DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME,
1550 		    VT_UNIT(vw), win);
1551 		if ((win > VT_MAXWINDOWS) || (win < 0))
1552 			return (EINVAL);
1553 		return (vt_proc_window_switch(vd->vd_windows[win]));
1554 	}
1555 	case VT_GETACTIVE:
1556 		*(int *)data = vd->vd_curwindow->vw_number + 1;
1557 		return (0);
1558 	case VT_GETINDEX:
1559 		*(int *)data = vw->vw_number + 1;
1560 		return (0);
1561 	case VT_LOCKSWITCH:
1562 		/* TODO: Check current state, switching can be in progress. */
1563 		if ((*(int *)data) & 0x01)
1564 			vw->vw_flags |= VWF_VTYLOCK;
1565 		else
1566 			vw->vw_flags &= ~VWF_VTYLOCK;
1567 	case VT_OPENQRY:
1568 		VT_LOCK(vd);
1569 		for (i = 0; i < VT_MAXWINDOWS; i++) {
1570 			vw = vd->vd_windows[i];
1571 			if (vw == NULL)
1572 				continue;
1573 			if (!(vw->vw_flags & VWF_OPENED)) {
1574 				*(int *)data = vw->vw_number + 1;
1575 				VT_UNLOCK(vd);
1576 				return (0);
1577 			}
1578 		}
1579 		VT_UNLOCK(vd);
1580 		return (EINVAL);
1581 	case VT_WAITACTIVE:
1582 		error = 0;
1583 
1584 		i = *(unsigned int *)data;
1585 		if (i > VT_MAXWINDOWS)
1586 			return (EINVAL);
1587 		if (i != 0)
1588 			vw = vd->vd_windows[i - 1];
1589 
1590 		VT_LOCK(vd);
1591 		while (vd->vd_curwindow != vw && error == 0)
1592 			error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
1593 		VT_UNLOCK(vd);
1594 		return (error);
1595 	case VT_SETMODE: {    	/* set screen switcher mode */
1596 		struct vt_mode *mode;
1597 		struct proc *p1;
1598 
1599 		mode = (struct vt_mode *)data;
1600 		DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw));
1601 		if (vw->vw_smode.mode == VT_PROCESS) {
1602 			p1 = pfind(vw->vw_pid);
1603 			if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) {
1604 				if (p1)
1605 					PROC_UNLOCK(p1);
1606 				DPRINTF(5, "error EPERM\n");
1607 				return (EPERM);
1608 			}
1609 			if (p1)
1610 				PROC_UNLOCK(p1);
1611 		}
1612 		if (mode->mode == VT_AUTO) {
1613 			vw->vw_smode.mode = VT_AUTO;
1614 			vw->vw_proc = NULL;
1615 			vw->vw_pid = 0;
1616 			DPRINTF(5, "VT_AUTO, ");
1617 			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1618 				cnavailable(vw->vw_terminal->consdev, TRUE);
1619 			/* were we in the middle of the vty switching process? */
1620 			if (finish_vt_rel(vw, TRUE, &s) == 0)
1621 				DPRINTF(5, "reset WAIT_REL, ");
1622 			if (finish_vt_acq(vw) == 0)
1623 				DPRINTF(5, "reset WAIT_ACQ, ");
1624 			return (0);
1625 		} else if (mode->mode == VT_PROCESS) {
1626 			if (!ISSIGVALID(mode->relsig) ||
1627 			    !ISSIGVALID(mode->acqsig) ||
1628 			    !ISSIGVALID(mode->frsig)) {
1629 				DPRINTF(5, "error EINVAL\n");
1630 				return (EINVAL);
1631 			}
1632 			DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid);
1633 			bcopy(data, &vw->vw_smode, sizeof(struct vt_mode));
1634 			vw->vw_proc = td->td_proc;
1635 			vw->vw_pid = vw->vw_proc->p_pid;
1636 			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1637 				cnavailable(vw->vw_terminal->consdev, FALSE);
1638 		} else {
1639 			DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n",
1640 			    mode->mode);
1641 			return (EINVAL);
1642 		}
1643 		DPRINTF(5, "\n");
1644 		return (0);
1645 	}
1646 	case VT_GETMODE:	/* get screen switcher mode */
1647 		bcopy(&vw->vw_smode, data, sizeof(struct vt_mode));
1648 		return (0);
1649 
1650 	case VT_RELDISP:	/* screen switcher ioctl */
1651 		/*
1652 		 * This must be the current vty which is in the VT_PROCESS
1653 		 * switching mode...
1654 		 */
1655 		if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode !=
1656 		    VT_PROCESS)) {
1657 			return (EINVAL);
1658 		}
1659 		/* ...and this process is controlling it. */
1660 		if (vw->vw_proc != td->td_proc) {
1661 			return (EPERM);
1662 		}
1663 		error = EINVAL;
1664 		switch(*(int *)data) {
1665 		case VT_FALSE:	/* user refuses to release screen, abort */
1666 			if ((error = finish_vt_rel(vw, FALSE, &s)) == 0)
1667 				DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n",
1668 				    SC_DRIVER_NAME, VT_UNIT(vw));
1669 			break;
1670 		case VT_TRUE:	/* user has released screen, go on */
1671 			/* finish_vt_rel(..., TRUE, ...) should not be locked */
1672 			if (vw->vw_flags & VWF_SWWAIT_REL) {
1673 				if ((error = finish_vt_rel(vw, TRUE, &s)) == 0)
1674 					DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n",
1675 					    SC_DRIVER_NAME, VT_UNIT(vw));
1676 			} else {
1677 				error = EINVAL;
1678 			}
1679 			return (error);
1680 		case VT_ACKACQ:	/* acquire acknowledged, switch completed */
1681 			if ((error = finish_vt_acq(vw)) == 0)
1682 				DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n",
1683 				    SC_DRIVER_NAME, VT_UNIT(vw));
1684 			break;
1685 		default:
1686 			break;
1687 		}
1688 		return (error);
1689 	}
1690 
1691 	return (ENOIOCTL);
1692 }
1693 
1694 static struct vt_window *
1695 vt_allocate_window(struct vt_device *vd, unsigned int window)
1696 {
1697 	struct vt_window *vw;
1698 	struct terminal *tm;
1699 	term_pos_t size;
1700 	struct winsize wsz;
1701 
1702 	vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO);
1703 	vw->vw_device = vd;
1704 	vw->vw_number = window;
1705 	vw->vw_kbdmode = K_XLATE;
1706 
1707 	if (!(vd->vd_flags & VDF_TEXTMODE))
1708 		vw->vw_font = vtfont_ref(&vt_font_default);
1709 
1710 	vt_termsize(vd, vw->vw_font, &size);
1711 	vt_winsize(vd, vw->vw_font, &wsz);
1712 	vtbuf_init(&vw->vw_buf, &size);
1713 
1714 	tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw);
1715 	terminal_set_winsize(tm, &wsz);
1716 	vd->vd_windows[window] = vw;
1717 	callout_init(&vw->vw_proc_dead_timer, 0);
1718 
1719 	return (vw);
1720 }
1721 
1722 void
1723 vt_upgrade(struct vt_device *vd)
1724 {
1725 	struct vt_window *vw;
1726 	unsigned int i;
1727 
1728 	/* Device didn't pass vd_init() or already upgraded. */
1729 	if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD))
1730 		return;
1731 	vd->vd_flags |= VDF_ASYNC;
1732 
1733 	mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF);
1734 	cv_init(&vd->vd_winswitch, "vtwswt");
1735 
1736 	/* Init 25 Hz timer. */
1737 	callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0);
1738 
1739 	for (i = 0; i < VT_MAXWINDOWS; i++) {
1740 		vw = vd->vd_windows[i];
1741 		if (vw == NULL) {
1742 			/* New window. */
1743 			vw = vt_allocate_window(vd, i);
1744 		}
1745 		if (i == VT_CONSWINDOW) {
1746 			/* Console window. */
1747 			EVENTHANDLER_REGISTER(shutdown_pre_sync,
1748 			    vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT);
1749 		}
1750 		terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw));
1751 	}
1752 	if (vd->vd_curwindow == NULL)
1753 		vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW];
1754 
1755 	/* Attach keyboard. */
1756 	vt_allocate_keyboard(vd);
1757 	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
1758 
1759 	/* Start timer when everything ready. */
1760 	callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd);
1761 }
1762 
1763 static void
1764 vt_resize(struct vt_device *vd)
1765 {
1766 	struct vt_window *vw;
1767 	int i;
1768 
1769 	for (i = 0; i < VT_MAXWINDOWS; i++) {
1770 		vw = vd->vd_windows[i];
1771 		/* Resize terminal windows */
1772 		vt_change_font(vw, vw->vw_font);
1773 	}
1774 }
1775 
1776 void
1777 vt_allocate(struct vt_driver *drv, void *softc)
1778 {
1779 	struct vt_device *vd;
1780 	struct winsize wsz;
1781 
1782 	if (main_vd == NULL) {
1783 		main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO);
1784 		printf("%s: VT initialize with new VT driver.\n", __func__);
1785 	} else {
1786 		/*
1787 		 * Check if have rights to replace current driver. For example:
1788 		 * it is bad idea to replace KMS driver with generic VGA one.
1789 		 */
1790 		if (drv->vd_priority <= main_vd->vd_driver->vd_priority) {
1791 			printf("%s: Driver priority %d too low. Current %d\n ",
1792 			    __func__, drv->vd_priority,
1793 			    main_vd->vd_driver->vd_priority);
1794 			return;
1795 		}
1796 		printf("%s: Replace existing VT driver.\n", __func__);
1797 	}
1798 	vd = main_vd;
1799 
1800 	/* Stop vt_flush periodic task. */
1801 	if (vd->vd_curwindow != NULL)
1802 		callout_drain(&vd->vd_timer);
1803 
1804 	vd->vd_driver = drv;
1805 	vd->vd_softc = softc;
1806 	vd->vd_driver->vd_init(vd);
1807 
1808 	vt_upgrade(vd);
1809 
1810 	/* Refill settings with new sizes. */
1811 	vt_resize(vd);
1812 
1813 #ifdef DEV_SPLASH
1814 	if (vd->vd_flags & VDF_SPLASH)
1815 		vtterm_splash(vd);
1816 #endif
1817 
1818 	if (vd->vd_curwindow != NULL)
1819 		callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
1820 
1821 	termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal);
1822 
1823 	/* Update console window sizes to actual. */
1824 	vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz);
1825 	terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz);
1826 }
1827 
1828 void
1829 vt_suspend()
1830 {
1831 
1832 	if (vt_suspendswitch == 0)
1833 		return;
1834 	/* Save current window. */
1835 	main_vd->vd_savedwindow = main_vd->vd_curwindow;
1836 	/* Ask holding process to free window and switch to console window */
1837 	vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]);
1838 }
1839 
1840 void
1841 vt_resume()
1842 {
1843 
1844 	if (vt_suspendswitch == 0)
1845 		return;
1846 	/* Switch back to saved window */
1847 	if (main_vd->vd_savedwindow != NULL)
1848 		vt_proc_window_switch(main_vd->vd_savedwindow);
1849 	main_vd->vd_savedwindow = NULL;
1850 }
1851