vt_core.c revision 256145
1/*-
2 * Copyright (c) 2009 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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/vt_core.c 256145 2013-10-08 12:40:04Z ray $");
32
33#include <sys/param.h>
34#include <sys/consio.h>
35#include <sys/eventhandler.h>
36#include <sys/fbio.h>
37#include <sys/kbio.h>
38#include <sys/kdb.h>
39#include <sys/kernel.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/mutex.h>
43#include <sys/proc.h>
44#include <sys/reboot.h>
45#include <sys/systm.h>
46#include <sys/terminal.h>
47
48#include <dev/kbd/kbdreg.h>
49#include <dev/vt/vt.h>
50
51static tc_bell_t	vtterm_bell;
52static tc_cursor_t	vtterm_cursor;
53static tc_putchar_t	vtterm_putchar;
54static tc_fill_t	vtterm_fill;
55static tc_copy_t	vtterm_copy;
56static tc_param_t	vtterm_param;
57static tc_done_t	vtterm_done;
58
59static tc_cnprobe_t	vtterm_cnprobe;
60static tc_cngetc_t	vtterm_cngetc;
61
62static tc_opened_t	vtterm_opened;
63static tc_ioctl_t	vtterm_ioctl;
64
65const struct terminal_class vt_termclass = {
66	.tc_bell	= vtterm_bell,
67	.tc_cursor	= vtterm_cursor,
68	.tc_putchar	= vtterm_putchar,
69	.tc_fill	= vtterm_fill,
70	.tc_copy	= vtterm_copy,
71	.tc_param	= vtterm_param,
72	.tc_done	= vtterm_done,
73
74	.tc_cnprobe	= vtterm_cnprobe,
75	.tc_cngetc	= vtterm_cngetc,
76
77	.tc_opened	= vtterm_opened,
78	.tc_ioctl	= vtterm_ioctl,
79};
80
81/*
82 * Use a constant timer of 25 Hz to redraw the screen.
83 *
84 * XXX: In theory we should only fire up the timer when there is really
85 * activity. Unfortunately we cannot always start timers. We really
86 * don't want to process kernel messages synchronously, because it
87 * really slows down the system.
88 */
89#define	VT_TIMERFREQ	25
90
91/* Bell pitch/duration. */
92#define VT_BELLDURATION	((5 * hz + 99) / 100)
93#define VT_BELLPITCH	800
94
95#define	VT_LOCK(vd)	mtx_lock(&(vd)->vd_lock)
96#define	VT_UNLOCK(vd)	mtx_unlock(&(vd)->vd_lock)
97
98#define	VT_UNIT(vw)	((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
99			(vw)->vw_number)
100
101/* XXX while syscons is here. */
102int sc_txtmouse_no_retrace_wait;
103
104static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters");
105VT_SYSCTL_INT(debug, 0, "Newcons debug level");
106VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
107
108static unsigned int vt_unit = 0;
109static MALLOC_DEFINE(M_VT, "vt", "vt device");
110struct vt_device *main_vd = NULL;
111
112/* Boot logo. */
113extern unsigned int vt_logo_width;
114extern unsigned int vt_logo_height;
115extern unsigned int vt_logo_depth;
116extern unsigned char vt_logo_image[];
117
118/* Font. */
119extern struct vt_font vt_font_default;
120
121static int signal_vt_rel(struct vt_window *);
122static int signal_vt_acq(struct vt_window *);
123static int finish_vt_rel(struct vt_window *, int, int *);
124static int finish_vt_acq(struct vt_window *);
125static int vt_window_switch(struct vt_window *);
126static int vt_late_window_switch(struct vt_window *);
127static int vt_proc_alive(struct vt_window *);
128static void vt_resize(struct vt_device *);
129
130static void
131vt_switch_timer(void *arg)
132{
133
134	vt_late_window_switch((struct vt_window *)arg);
135}
136
137static int
138vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
139{
140
141	DPRINTF(40, "%s\n", __func__);
142	curvw->vw_switch_to = vw;
143	/* Set timer to allow switch in case when process hang. */
144	callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer,
145	    vt_switch_timer, (void *)vw);
146	/* Notify process about vt switch attempt. */
147	DPRINTF(30, "%s: Notify process.\n", __func__);
148	signal_vt_rel(curvw);
149
150	return (0);
151}
152
153static int
154vt_window_postswitch(struct vt_window *vw)
155{
156
157	signal_vt_acq(vw);
158	return (0);
159}
160
161/* vt_late_window_switch will done VT switching for regular case. */
162static int
163vt_late_window_switch(struct vt_window *vw)
164{
165	int ret;
166
167	callout_stop(&vw->vw_proc_dead_timer);
168
169	ret = vt_window_switch(vw);
170	if (ret)
171		return (ret);
172
173	/* Notify owner process about terminal availability. */
174	if (vw->vw_smode.mode == VT_PROCESS) {
175		ret = vt_window_postswitch(vw);
176	}
177	return (ret);
178}
179
180/* Switch window. */
181static int
182vt_proc_window_switch(struct vt_window *vw)
183{
184	struct vt_window *curvw;
185	struct vt_device *vd;
186	int ret;
187
188	if (vw->vw_flags & VWF_VTYLOCK)
189		return (EBUSY);
190
191	vd = vw->vw_device;
192	curvw = vd->vd_curwindow;
193
194	/* Ask current process permitions to switch away. */
195	if (curvw->vw_smode.mode == VT_PROCESS) {
196		DPRINTF(30, "%s: VT_PROCESS ", __func__);
197		if (vt_proc_alive(curvw) == FALSE) {
198			DPRINTF(30, "Dead. Cleaning.");
199			/* Dead */
200		} else {
201			DPRINTF(30, "%s: Signaling process.\n", __func__);
202			/* Alive, try to ask him. */
203			ret = vt_window_preswitch(vw, curvw);
204			/* Wait for process answer or timeout. */
205			return (ret);
206		}
207		DPRINTF(30, "\n");
208	}
209
210	ret = vt_late_window_switch(vw);
211	return (ret);
212}
213
214/* Switch window ignoring process locking. */
215static int
216vt_window_switch(struct vt_window *vw)
217{
218	struct vt_device *vd = vw->vw_device;
219	struct vt_window *curvw = vd->vd_curwindow;
220	keyboard_t *kbd;
221
222	VT_LOCK(vd);
223	if (curvw == vw) {
224		/* Nothing to do. */
225		VT_UNLOCK(vd);
226		return (0);
227	}
228	if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
229		VT_UNLOCK(vd);
230		return (EINVAL);
231	}
232
233	vd->vd_curwindow = vw;
234	vd->vd_flags |= VDF_INVALID;
235	cv_broadcast(&vd->vd_winswitch);
236	VT_UNLOCK(vd);
237
238	if (vd->vd_driver->vd_postswitch)
239		vd->vd_driver->vd_postswitch(vd);
240
241	/* Restore per-window keyboard mode. */
242	mtx_lock(&Giant);
243	kbd = kbd_get_keyboard(vd->vd_keyboard);
244	if (kbd != NULL) {
245		kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode);
246	}
247	mtx_unlock(&Giant);
248	DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
249
250	return (0);
251}
252
253static inline void
254vt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size)
255{
256
257	size->tp_row = vd->vd_height;
258	size->tp_col = vd->vd_width;
259	if (vf != NULL) {
260		size->tp_row /= vf->vf_height;
261		size->tp_col /= vf->vf_width;
262	}
263}
264
265static inline void
266vt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size)
267{
268
269	size->ws_row = size->ws_ypixel = vd->vd_height;
270	size->ws_col = size->ws_xpixel = vd->vd_width;
271	if (vf != NULL) {
272		size->ws_row /= vf->vf_height;
273		size->ws_col /= vf->vf_width;
274	}
275}
276
277static int
278vt_kbdevent(keyboard_t *kbd, int event, void *arg)
279{
280	struct vt_device *vd = arg;
281	struct vt_window *vw = vd->vd_curwindow;
282	int c;
283
284	switch (event) {
285	case KBDIO_KEYINPUT:
286		break;
287	case KBDIO_UNLOADING:
288		mtx_lock(&Giant);
289		vd->vd_keyboard = -1;
290		kbd_release(kbd, (void *)&vd->vd_keyboard);
291		mtx_unlock(&Giant);
292		return (0);
293	default:
294		return (EINVAL);
295	}
296
297	c = kbdd_read_char(kbd, 0);
298	if (c & RELKEY)
299		return (0);
300
301	if (c & SPCLKEY) {
302		c &= ~SPCLKEY;
303
304		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
305			vw = vd->vd_windows[c - F_SCR];
306			if (vw != NULL)
307				vt_proc_window_switch(vw);
308			return (0);
309		}
310
311		switch (c) {
312		case DBG:
313			kdb_enter(KDB_WHY_BREAK, "manual escape to debugger");
314			break;
315		case RBT:
316			/* XXX: Make this configurable! */
317			shutdown_nice(0);
318			break;
319		case HALT:
320			shutdown_nice(RB_HALT);
321			break;
322		case PDWN:
323			shutdown_nice(RB_HALT|RB_POWEROFF);
324			break;
325		case SLK: {
326			int state = 0;
327
328			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
329			VT_LOCK(vd);
330			if (state & SLKED) {
331				/* Turn scrolling on. */
332				vw->vw_flags |= VWF_SCROLL;
333				VTBUF_SLCK_ENABLE(&vw->vw_buf);
334			} else {
335				/* Turn scrolling off. */
336				vw->vw_flags &= ~VWF_SCROLL;
337				VTBUF_SLCK_DISABLE(&vw->vw_buf);
338				vthistory_seek(&vw->vw_buf, 0, VHS_END);
339				vd->vd_flags |= VDF_INVALID;
340			}
341			VT_UNLOCK(vd);
342			break;
343		}
344		case FKEY | F(1):  case FKEY | F(2):  case FKEY | F(3):
345		case FKEY | F(4):  case FKEY | F(5):  case FKEY | F(6):
346		case FKEY | F(7):  case FKEY | F(8):  case FKEY | F(9):
347		case FKEY | F(10): case FKEY | F(11): case FKEY | F(12):
348			/* F1 through F12 keys. */
349			terminal_input_special(vw->vw_terminal,
350			    TKEY_F1 + c - (FKEY | F(1)));
351			break;
352		case FKEY | F(49): /* Home key. */
353			VT_LOCK(vd);
354			if (vw->vw_flags & VWF_SCROLL) {
355				if (vthistory_seek(&vw->vw_buf, 0, VHS_END))
356					vd->vd_flags |= VDF_INVALID;
357				VT_UNLOCK(vd);
358				break;
359			}
360			VT_UNLOCK(vd);
361			terminal_input_special(vw->vw_terminal, TKEY_HOME);
362			break;
363		case FKEY | F(50): /* Arrow up. */
364			VT_LOCK(vd);
365			if (vw->vw_flags & VWF_SCROLL) {
366				if (vthistory_seek(&vw->vw_buf, -1, VHS_CUR))
367					vd->vd_flags |= VDF_INVALID;
368				VT_UNLOCK(vd);
369				break;
370			}
371			VT_UNLOCK(vd);
372			terminal_input_special(vw->vw_terminal, TKEY_UP);
373			break;
374		case FKEY | F(51): /* Page up. */
375			VT_LOCK(vd);
376			if (vw->vw_flags & VWF_SCROLL) {
377				term_pos_t size;
378
379				vt_termsize(vd, vw->vw_font, &size);
380				if (vthistory_seek(&vw->vw_buf, -size.tp_row,
381				    VHS_CUR))
382					vd->vd_flags |= VDF_INVALID;
383				VT_UNLOCK(vd);
384				break;
385			}
386			VT_UNLOCK(vd);
387			terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP);
388			break;
389		case FKEY | F(53): /* Arrow left. */
390			terminal_input_special(vw->vw_terminal, TKEY_LEFT);
391			break;
392		case FKEY | F(55): /* Arrow right. */
393			terminal_input_special(vw->vw_terminal, TKEY_RIGHT);
394			break;
395		case FKEY | F(57): /* End key. */
396			VT_LOCK(vd);
397			if (vw->vw_flags & VWF_SCROLL) {
398				if (vthistory_seek(&vw->vw_buf, 0, VHS_SET))
399					vd->vd_flags |= VDF_INVALID;
400				VT_UNLOCK(vd);
401				break;
402			}
403			VT_UNLOCK(vd);
404			terminal_input_special(vw->vw_terminal, TKEY_END);
405			break;
406		case FKEY | F(58): /* Arrow down. */
407			VT_LOCK(vd);
408			if (vw->vw_flags & VWF_SCROLL) {
409				if (vthistory_seek(&vw->vw_buf, 1, VHS_CUR))
410					vd->vd_flags |= VDF_INVALID;
411				VT_UNLOCK(vd);
412				break;
413			}
414			VT_UNLOCK(vd);
415			terminal_input_special(vw->vw_terminal, TKEY_DOWN);
416			break;
417		case FKEY | F(59): /* Page down. */
418			VT_LOCK(vd);
419			if (vw->vw_flags & VWF_SCROLL) {
420				term_pos_t size;
421
422				vt_termsize(vd, vw->vw_font, &size);
423				if (vthistory_seek(&vw->vw_buf, size.tp_row,
424				    VHS_CUR))
425					vd->vd_flags |= VDF_INVALID;
426				VT_UNLOCK(vd);
427				break;
428			}
429			VT_UNLOCK(vd);
430			terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN);
431			break;
432		case FKEY | F(60): /* Insert key. */
433			terminal_input_special(vw->vw_terminal, TKEY_INSERT);
434			break;
435		case FKEY | F(61): /* Delete key. */
436			terminal_input_special(vw->vw_terminal, TKEY_DELETE);
437			break;
438		}
439	} else if (KEYFLAGS(c) == 0) {
440		/* Don't do UTF-8 conversion when doing raw mode. */
441		if (vw->vw_kbdmode == K_XLATE)
442			terminal_input_char(vw->vw_terminal, KEYCHAR(c));
443		else
444			terminal_input_raw(vw->vw_terminal, c);
445	}
446	return (0);
447}
448
449static int
450vt_allocate_keyboard(struct vt_device *vd)
451{
452	int		 idx0, idx;
453	keyboard_t	*k0, *k;
454	keyboard_info_t	 ki;
455
456	idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard,
457	    vt_kbdevent, vd);
458	/* XXX: kb_token lost */
459	vd->vd_keyboard = idx0;
460	if (idx0 != -1) {
461		DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
462		k0 = kbd_get_keyboard(idx0);
463
464		for (idx = kbd_find_keyboard2("*", -1, 0);
465		     idx != -1;
466		     idx = kbd_find_keyboard2("*", -1, idx + 1)) {
467			k = kbd_get_keyboard(idx);
468
469			if (idx == idx0 || KBD_IS_BUSY(k))
470				continue;
471
472			bzero(&ki, sizeof(ki));
473			strcpy(ki.kb_name, k->kb_name);
474			ki.kb_unit = k->kb_unit;
475
476			kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
477		}
478	} else {
479		DPRINTF(20, "%s: no kbdmux allocated\n", __func__);
480		idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard,
481		    vt_kbdevent, vd);
482	}
483	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
484
485	return (idx0);
486}
487
488static void
489vtterm_bell(struct terminal *tm)
490{
491
492	sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION);
493}
494
495static void
496vtterm_cursor(struct terminal *tm, const term_pos_t *p)
497{
498	struct vt_window *vw = tm->tm_softc;
499
500	vtbuf_cursor_position(&vw->vw_buf, p);
501}
502
503static void
504vtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c)
505{
506	struct vt_window *vw = tm->tm_softc;
507
508	vtbuf_putchar(&vw->vw_buf, p, c);
509}
510
511static void
512vtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c)
513{
514	struct vt_window *vw = tm->tm_softc;
515
516	vtbuf_fill_locked(&vw->vw_buf, r, c);
517}
518
519static void
520vtterm_copy(struct terminal *tm, const term_rect_t *r,
521    const term_pos_t *p)
522{
523	struct vt_window *vw = tm->tm_softc;
524
525	vtbuf_copy(&vw->vw_buf, r, p);
526}
527
528static void
529vtterm_param(struct terminal *tm, int cmd, unsigned int arg)
530{
531	struct vt_window *vw = tm->tm_softc;
532
533	switch (cmd) {
534	case TP_SHOWCURSOR:
535		vtbuf_cursor_visibility(&vw->vw_buf, arg);
536		break;
537	}
538}
539
540static inline void
541vt_determine_colors(term_char_t c, int cursor,
542    term_color_t *fg, term_color_t *bg)
543{
544
545	*fg = TCHAR_FGCOLOR(c);
546	if (TCHAR_FORMAT(c) & TF_BOLD)
547		*fg = TCOLOR_LIGHT(*fg);
548	*bg = TCHAR_BGCOLOR(c);
549
550	if (TCHAR_FORMAT(c) & TF_REVERSE) {
551		term_color_t tmp;
552
553		tmp = *fg;
554		*fg = *bg;
555		*bg = tmp;
556	}
557
558	if (cursor) {
559		*fg = *bg;
560		*bg = TC_WHITE;
561	}
562}
563
564static void
565vt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c,
566    int iscursor, unsigned int row, unsigned int col)
567{
568	term_color_t fg, bg;
569
570	vt_determine_colors(c, iscursor, &fg, &bg);
571
572	if (vf != NULL) {
573		const uint8_t *src;
574		vt_axis_t top, left;
575
576		src = vtfont_lookup(vf, c);
577
578		/*
579		 * Align the terminal to the centre of the screen.
580		 * Fonts may not always be able to fill the entire
581		 * screen.
582		 */
583		top = row * vf->vf_height +
584		    (vd->vd_height % vf->vf_height) / 2;
585		left = col * vf->vf_width +
586		    (vd->vd_width % vf->vf_width) / 2;
587
588		vd->vd_driver->vd_bitblt(vd, src, top, left,
589		    vf->vf_width, vf->vf_height, fg, bg);
590	} else {
591		vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c),
592		    row, col, fg, bg);
593	}
594}
595
596static void
597vt_flush(struct vt_device *vd)
598{
599	struct vt_window *vw = vd->vd_curwindow;
600	struct vt_font *vf = vw->vw_font;
601	term_pos_t size;
602	term_rect_t tarea;
603	struct vt_bufmask tmask;
604	unsigned int row, col;
605	term_char_t *r;
606
607	if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
608		return;
609
610	vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
611	vt_termsize(vd, vf, &size);
612
613	/* Force a full redraw when the screen contents are invalid. */
614	if (vd->vd_flags & VDF_INVALID) {
615		tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0;
616		tarea.tr_end = size;
617		tmask.vbm_row = tmask.vbm_col = VBM_DIRTY;
618
619		/*
620		 * Blank to prevent borders with artifacts.  This is
621		 * only required when the font doesn't exactly fill the
622		 * screen.
623		 */
624		if (vd->vd_flags & VDF_INVALID && vf != NULL &&
625		    (vd->vd_width % vf->vf_width != 0 ||
626		    vd->vd_height % vf->vf_height != 0))
627			vd->vd_driver->vd_blank(vd, TC_BLACK);
628
629		vd->vd_flags &= ~VDF_INVALID;
630	}
631
632
633	for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) {
634		if (!VTBUF_DIRTYROW(&tmask, row))
635			continue;
636		r = VTBUF_GET_ROW(&vw->vw_buf, row);
637		for (col = tarea.tr_begin.tp_col;
638		    col < tarea.tr_end.tp_col; col++) {
639			if (!VTBUF_DIRTYCOL(&tmask, col))
640				continue;
641
642			vt_bitblt_char(vd, vf, r[col],
643			    VTBUF_ISCURSOR(&vw->vw_buf, row, col),
644			    row, col);
645		}
646	}
647}
648
649static void
650vt_timer(void *arg)
651{
652	struct vt_device *vd = arg;
653	unsigned int i;
654
655	vt_flush(vd);
656
657	for (i = 0; i < VT_MAXWINDOWS; i++)
658		vt_proc_alive(vd->vd_windows[i]);
659
660	callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
661}
662
663static void
664vtterm_done(struct terminal *tm)
665{
666	struct vt_window *vw = tm->tm_softc;
667	struct vt_device *vd = vw->vw_device;
668
669	if (kdb_active || panicstr != NULL) {
670		/* Switch to the debugger. */
671		if (vd->vd_curwindow != vw) {
672			vd->vd_curwindow = vw;
673			vd->vd_flags |= VDF_INVALID;
674		}
675		vd->vd_flags &= ~VDF_SPLASH;
676		vt_flush(vd);
677	} else if (!(vd->vd_flags & VDF_ASYNC)) {
678		vt_flush(vd);
679	}
680}
681
682static void
683vtterm_splash(struct vt_device *vd)
684{
685	vt_axis_t top, left;
686
687	/* Display a nice boot splash. */
688	if (!(vd->vd_flags & VDF_TEXTMODE)) {
689
690		top = (vd->vd_height - vt_logo_height) / 2;
691		left = (vd->vd_width - vt_logo_width) / 2;
692		switch (vt_logo_depth) {
693		case 1:
694			/* XXX: Unhardcode colors! */
695			vd->vd_driver->vd_bitblt(vd, vt_logo_image, top, left,
696			    vt_logo_width, vt_logo_height, 0xf, 0x0);
697		}
698		vd->vd_flags |= VDF_SPLASH;
699	}
700}
701
702static void
703vtterm_cnprobe(struct terminal *tm, struct consdev *cp)
704{
705	struct vt_window *vw = tm->tm_softc;
706	struct vt_device *vd = vw->vw_device;
707	struct winsize wsz;
708
709	if (vd->vd_flags & VDF_INITIALIZED)
710		/* Initialization already done. */
711		return;
712
713	cp->cn_pri = vd->vd_driver->vd_init(vd);
714	if (cp->cn_pri == CN_DEAD) {
715		vd->vd_flags |= VDF_DEAD;
716		return;
717	}
718
719	/* Initialize any early-boot keyboard drivers */
720	kbd_configure(KB_CONF_PROBE_ONLY);
721
722	vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1);
723	vd->vd_windows[VT_CONSWINDOW] = vw;
724	sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw));
725
726	if (!(vd->vd_flags & VDF_TEXTMODE))
727		vw->vw_font = vtfont_ref(&vt_font_default);
728
729	vtbuf_init_early(&vw->vw_buf);
730	vt_winsize(vd, vw->vw_font, &wsz);
731	terminal_set_winsize(tm, &wsz);
732
733	vtterm_splash(vd);
734
735	vd->vd_flags |= VDF_INITIALIZED;
736	main_vd = vd;
737}
738
739static int
740vtterm_cngetc(struct terminal *tm)
741{
742	struct vt_window *vw = tm->tm_softc;
743	struct vt_device *vd = vw->vw_device;
744	keyboard_t *kbd;
745	u_int c;
746
747	/* Make sure the splash screen is not there. */
748	if (vd->vd_flags & VDF_SPLASH) {
749		/* Remove splash */
750		vd->vd_flags &= ~VDF_SPLASH;
751		/* Mark screen as invalid to force update */
752		vd->vd_flags |= VDF_INVALID;
753		vt_flush(vd);
754	}
755
756	/* Stripped down keyboard handler. */
757	kbd = kbd_get_keyboard(vd->vd_keyboard);
758	if (kbd == NULL)
759		return (-1);
760
761	/* Force keyboard input mode to K_XLATE */
762	c = K_XLATE;
763	kbdd_ioctl(kbd, KDSKBMODE, (void *)&c);
764
765	/* Switch the keyboard to polling to make it work here. */
766	kbdd_poll(kbd, TRUE);
767	c = kbdd_read_char(kbd, 0);
768	kbdd_poll(kbd, FALSE);
769	if (c & RELKEY)
770		return (-1);
771
772	/* Stripped down handling of vt_kbdevent(), without locking, etc. */
773	if (c & SPCLKEY) {
774		c &= ~SPCLKEY;
775
776		switch (c) {
777		case SLK: {
778			int state = 0;
779
780			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
781			if (state & SLKED) {
782				/* Turn scrolling on. */
783				vw->vw_flags |= VWF_SCROLL;
784				VTBUF_SLCK_ENABLE(&vw->vw_buf);
785			} else {
786				/* Turn scrolling off. */
787				vw->vw_flags &= ~VWF_SCROLL;
788				VTBUF_SLCK_DISABLE(&vw->vw_buf);
789				vthistory_seek(&vw->vw_buf, 0, VHS_END);
790				vd->vd_flags |= VDF_INVALID;
791			}
792			break;
793		}
794		case FKEY | F(49): /* Home key. */
795			if (vw->vw_flags & VWF_SCROLL)
796				if (vthistory_seek(&vw->vw_buf, 0, VHS_END))
797					vd->vd_flags |= VDF_INVALID;
798			break;
799		case FKEY | F(50): /* Arrow up. */
800			if (vw->vw_flags & VWF_SCROLL)
801				if (vthistory_seek(&vw->vw_buf, -1, VHS_CUR))
802					vd->vd_flags |= VDF_INVALID;
803			break;
804		case FKEY | F(51): /* Page up. */
805			if (vw->vw_flags & VWF_SCROLL) {
806				term_pos_t size;
807
808				vt_termsize(vd, vw->vw_font, &size);
809				if (vthistory_seek(&vw->vw_buf, -size.tp_row,
810				    VHS_CUR))
811					vd->vd_flags |= VDF_INVALID;
812			}
813			break;
814		case FKEY | F(57): /* End key. */
815			if (vw->vw_flags & VWF_SCROLL)
816				if (vthistory_seek(&vw->vw_buf, 0, VHS_SET))
817					vd->vd_flags |= VDF_INVALID;
818			break;
819		case FKEY | F(58): /* Arrow down. */
820			if (vw->vw_flags & VWF_SCROLL)
821				if (vthistory_seek(&vw->vw_buf, 1, VHS_CUR))
822					vd->vd_flags |= VDF_INVALID;
823			break;
824		case FKEY | F(59): /* Page down. */
825			if (vw->vw_flags & VWF_SCROLL) {
826				term_pos_t size;
827
828				vt_termsize(vd, vw->vw_font, &size);
829				if (vthistory_seek(&vw->vw_buf, size.tp_row,
830				    VHS_CUR))
831					vd->vd_flags |= VDF_INVALID;
832			}
833			break;
834		}
835
836		/* Force refresh to make scrollback work. */
837		vt_flush(vd);
838	} else if (KEYFLAGS(c) == 0) {
839		return KEYCHAR(c);
840	}
841
842	return (-1);
843}
844
845static void
846vtterm_opened(struct terminal *tm, int opened)
847{
848	struct vt_window *vw = tm->tm_softc;
849	struct vt_device *vd = vw->vw_device;
850
851	VT_LOCK(vd);
852	vd->vd_flags &= ~VDF_SPLASH;
853	if (opened)
854		vw->vw_flags |= VWF_OPENED;
855	else {
856		vw->vw_flags &= ~VWF_OPENED;
857		/* TODO: finish ACQ/REL */
858	}
859	VT_UNLOCK(vd);
860}
861
862static int
863vt_change_font(struct vt_window *vw, struct vt_font *vf)
864{
865	struct vt_device *vd = vw->vw_device;
866	struct terminal *tm = vw->vw_terminal;
867	term_pos_t size;
868	struct winsize wsz;
869
870	/*
871	 * Changing fonts.
872	 *
873	 * Changing fonts is a little tricky.  We must prevent
874	 * simultaneous access to the device, so we must stop
875	 * the display timer and the terminal from accessing.
876	 * We need to switch fonts and grow our screen buffer.
877	 *
878	 * XXX: Right now the code uses terminal_mute() to
879	 * prevent data from reaching the console driver while
880	 * resizing the screen buffer.  This isn't elegant...
881	 */
882
883	VT_LOCK(vd);
884	if (vw->vw_flags & VWF_BUSY) {
885		/* Another process is changing the font. */
886		VT_UNLOCK(vd);
887		return (EBUSY);
888	}
889	if (vw->vw_font == NULL) {
890		/* Our device doesn't need fonts. */
891		VT_UNLOCK(vd);
892		return (ENOTTY);
893	}
894	vw->vw_flags |= VWF_BUSY;
895	VT_UNLOCK(vd);
896
897	vt_termsize(vd, vf, &size);
898	vt_winsize(vd, vf, &wsz);
899
900	/* Grow the screen buffer and terminal. */
901	terminal_mute(tm, 1);
902	vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
903	terminal_set_winsize(tm, &wsz);
904	terminal_mute(tm, 0);
905
906	/* Actually apply the font to the current window. */
907	VT_LOCK(vd);
908	vtfont_unref(vw->vw_font);
909	vw->vw_font = vtfont_ref(vf);
910
911	/* Force a full redraw the next timer tick. */
912	if (vd->vd_curwindow == vw)
913		vd->vd_flags |= VDF_INVALID;
914	vw->vw_flags &= ~VWF_BUSY;
915	VT_UNLOCK(vd);
916	return (0);
917}
918
919static int
920vt_proc_alive(struct vt_window *vw)
921{
922	struct proc *p;
923
924	if (vw->vw_smode.mode != VT_PROCESS)
925		return FALSE;
926
927	if (vw->vw_proc) {
928		if ((p = pfind(vw->vw_pid)) != NULL)
929			PROC_UNLOCK(p);
930		if (vw->vw_proc == p)
931			return TRUE;
932		vw->vw_proc = NULL;
933		vw->vw_smode.mode = VT_AUTO;
934		DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid);
935		vw->vw_pid = 0;
936	}
937	return FALSE;
938}
939
940static int
941signal_vt_rel(struct vt_window *vw)
942{
943	if (vw->vw_smode.mode != VT_PROCESS)
944		return FALSE;
945	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
946		vw->vw_proc = NULL;
947		vw->vw_pid = 0;
948		return TRUE;
949	}
950	vw->vw_flags |= VWF_SWWAIT_REL;
951	PROC_LOCK(vw->vw_proc);
952	kern_psignal(vw->vw_proc, vw->vw_smode.relsig);
953	PROC_UNLOCK(vw->vw_proc);
954	DPRINTF(1, "sending relsig to %d\n", vw->vw_pid);
955	return TRUE;
956}
957
958static int
959signal_vt_acq(struct vt_window *vw)
960{
961	if (vw->vw_smode.mode != VT_PROCESS)
962		return FALSE;
963	if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
964		cnavailable(vw->vw_terminal->consdev, FALSE);
965	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
966		vw->vw_proc = NULL;
967		vw->vw_pid = 0;
968		return TRUE;
969	}
970	vw->vw_flags |= VWF_SWWAIT_ACQ;
971	PROC_LOCK(vw->vw_proc);
972	kern_psignal(vw->vw_proc, vw->vw_smode.acqsig);
973	PROC_UNLOCK(vw->vw_proc);
974	DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid);
975	return TRUE;
976}
977
978static int
979finish_vt_rel(struct vt_window *vw, int release, int *s)
980{
981	if (vw->vw_flags & VWF_SWWAIT_REL) {
982		vw->vw_flags &= ~VWF_SWWAIT_REL;
983		if (release) {
984			callout_drain(&vw->vw_proc_dead_timer);
985			vt_late_window_switch(vw->vw_switch_to);
986		}
987		return 0;
988	}
989	return EINVAL;
990}
991
992static int
993finish_vt_acq(struct vt_window *vw)
994{
995	if (vw->vw_flags & VWF_SWWAIT_ACQ) {
996		vw->vw_flags &= ~VWF_SWWAIT_ACQ;
997		return 0;
998	}
999	return EINVAL;
1000}
1001
1002static int
1003vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
1004    struct thread *td)
1005{
1006	struct vt_window *vw = tm->tm_softc;
1007	struct vt_device *vd = vw->vw_device;
1008	int error, s;
1009
1010	switch (cmd) {
1011	case GIO_KEYMAP:
1012	case PIO_KEYMAP:
1013	case GIO_DEADKEYMAP:
1014	case PIO_DEADKEYMAP:
1015	case GETFKEY:
1016	case SETFKEY:
1017	case KDGKBINFO: {
1018		keyboard_t *kbd;
1019		error = 0;
1020
1021		mtx_lock(&Giant);
1022		kbd = kbd_get_keyboard(vd->vd_keyboard);
1023		if (kbd != NULL)
1024			error = kbdd_ioctl(kbd, cmd, data);
1025		mtx_unlock(&Giant);
1026		if (error == ENOIOCTL)
1027			return (ENODEV);
1028		return (error);
1029	}
1030	case KDGKBMODE: {
1031		int mode = -1;
1032		keyboard_t *kbd;
1033
1034		mtx_lock(&Giant);
1035		kbd = kbd_get_keyboard(vd->vd_keyboard);
1036		if (kbd != NULL) {
1037			kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode);
1038		}
1039		mtx_unlock(&Giant);
1040		DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode);
1041		*(int *)data = mode;
1042		return (0);
1043	}
1044	case KDSKBMODE: {
1045		int mode;
1046
1047		mode = *(int *)data;
1048		switch (mode) {
1049		case K_XLATE:
1050		case K_RAW:
1051		case K_CODE:
1052			vw->vw_kbdmode = mode;
1053			if (vw == vd->vd_curwindow) {
1054				keyboard_t *kbd;
1055				error = 0;
1056
1057				DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
1058				mtx_lock(&Giant);
1059				kbd = kbd_get_keyboard(vd->vd_keyboard);
1060				if (kbd != NULL) {
1061					DPRINTF(20, "kbdd_ioctl(KDSKBMODE, %d)\n", mode);
1062					error = kbdd_ioctl(kbd, KDSKBMODE,
1063					    (void *)&mode);
1064				}
1065				mtx_unlock(&Giant);
1066				if (error)
1067					DPRINTF(20, "kbdd_ioctl(KDSKBMODE) return %d\n", error);
1068			}
1069			return (0);
1070		default:
1071			return (EINVAL);
1072		}
1073	}
1074	case CONS_BLANKTIME:
1075		/* XXX */
1076		return (0);
1077	case CONS_GET:
1078		/* XXX */
1079		*(int *)data = M_CG640x480;
1080		return (0);
1081	case CONS_GETINFO: {
1082		vid_info_t *vi = (vid_info_t *)data;
1083
1084		vi->m_num = vd->vd_curwindow->vw_number + 1;
1085		/* XXX: other fields! */
1086		return (0);
1087	}
1088	case CONS_GETVERS:
1089		*(int *)data = 0x200;
1090		return 0;
1091	case CONS_MODEINFO:
1092		/* XXX */
1093		return (0);
1094	case CONS_MOUSECTL: {
1095		mouse_info_t *mouse = (mouse_info_t*)data;
1096
1097		/*
1098		 * This has no effect on vt(4).  We don't draw any mouse
1099		 * cursor.  Just ignore MOUSE_HIDE and MOUSE_SHOW to
1100		 * prevent excessive errors.  All the other commands
1101		 * should not be applied to individual TTYs, but only to
1102		 * consolectl.
1103		 */
1104		switch (mouse->operation) {
1105		case MOUSE_HIDE:
1106		case MOUSE_SHOW:
1107			return (0);
1108		default:
1109			return (EINVAL);
1110		}
1111	}
1112	case PIO_VFONT: {
1113		struct vt_font *vf;
1114
1115		error = vtfont_load((void *)data, &vf);
1116		if (error != 0)
1117			return (error);
1118
1119		error = vt_change_font(vw, vf);
1120		vtfont_unref(vf);
1121		return (error);
1122	}
1123	case GIO_SCRNMAP: {
1124		scrmap_t *sm = (scrmap_t *)data;
1125		int i;
1126
1127		/* We don't have screen maps, so return a handcrafted one. */
1128		for (i = 0; i < 256; i++)
1129			sm->scrmap[i] = i;
1130		return (0);
1131	}
1132	case KDGETLED:
1133		/* XXX */
1134		return (0);
1135	case KDSETLED:
1136		/* XXX */
1137		return (0);
1138	case KDSETMODE:
1139		/* XXX */
1140		return (0);
1141	case KDSETRAD:
1142		/* XXX */
1143		return (0);
1144	case VT_ACTIVATE: {
1145		int win;
1146		win = *(int *)data - 1;
1147		DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, VT_UNIT(vw), win);
1148		if ((win > VT_MAXWINDOWS) || (win < 0))
1149			return (EINVAL);
1150		return (vt_proc_window_switch(vd->vd_windows[win]));
1151	}
1152	case VT_GETACTIVE:
1153		*(int *)data = vd->vd_curwindow->vw_number + 1;
1154		return (0);
1155	case VT_GETINDEX:
1156		*(int *)data = vw->vw_number + 1;
1157		return (0);
1158	case VT_LOCKSWITCH:
1159		/* TODO: Check current state, switching can be in progress. */
1160		if ((*(int *)data) & 0x01)
1161			vw->vw_flags |= VWF_VTYLOCK;
1162		else
1163			vw->vw_flags &= ~VWF_VTYLOCK;
1164	case VT_OPENQRY: {
1165		unsigned int i;
1166
1167		VT_LOCK(vd);
1168		for (i = 0; i < VT_MAXWINDOWS; i++) {
1169			vw = vd->vd_windows[i];
1170			if (vw == NULL)
1171				continue;
1172			if (!(vw->vw_flags & VWF_OPENED)) {
1173				*(int *)data = vw->vw_number + 1;
1174				VT_UNLOCK(vd);
1175				return (0);
1176			}
1177		}
1178		VT_UNLOCK(vd);
1179		return (EINVAL);
1180	}
1181	case VT_WAITACTIVE: {
1182		unsigned int i;
1183		error = 0;
1184
1185		i = *(unsigned int *)data;
1186		if (i > VT_MAXWINDOWS)
1187			return (EINVAL);
1188		if (i != 0)
1189			vw = vd->vd_windows[i - 1];
1190
1191		VT_LOCK(vd);
1192		while (vd->vd_curwindow != vw && error == 0)
1193			error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
1194		VT_UNLOCK(vd);
1195		return (error);
1196	}
1197	case VT_SETMODE:    	/* set screen switcher mode */
1198	{
1199		struct vt_mode *mode;
1200		struct proc *p1;
1201
1202		mode = (struct vt_mode *)data;
1203		DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw));
1204		if (vw->vw_smode.mode == VT_PROCESS) {
1205			p1 = pfind(vw->vw_pid);
1206			if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) {
1207				if (p1)
1208					PROC_UNLOCK(p1);
1209				DPRINTF(5, "error EPERM\n");
1210				return (EPERM);
1211			}
1212			if (p1)
1213				PROC_UNLOCK(p1);
1214		}
1215		if (mode->mode == VT_AUTO) {
1216			vw->vw_smode.mode = VT_AUTO;
1217			vw->vw_proc = NULL;
1218			vw->vw_pid = 0;
1219			DPRINTF(5, "VT_AUTO, ");
1220			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1221				cnavailable(vw->vw_terminal->consdev, TRUE);
1222			/* were we in the middle of the vty switching process? */
1223			if (finish_vt_rel(vw, TRUE, &s) == 0)
1224				DPRINTF(5, "reset WAIT_REL, ");
1225			if (finish_vt_acq(vw) == 0)
1226				DPRINTF(5, "reset WAIT_ACQ, ");
1227			return (0);
1228		} else if (mode->mode == VT_PROCESS) {
1229			if (!ISSIGVALID(mode->relsig) ||
1230			    !ISSIGVALID(mode->acqsig) ||
1231			    !ISSIGVALID(mode->frsig)) {
1232				DPRINTF(5, "error EINVAL\n");
1233				return (EINVAL);
1234			}
1235			DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid);
1236			bcopy(data, &vw->vw_smode, sizeof(struct vt_mode));
1237			vw->vw_proc = td->td_proc;
1238			vw->vw_pid = vw->vw_proc->p_pid;
1239			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1240				cnavailable(vw->vw_terminal->consdev, FALSE);
1241		} else {
1242			DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n",
1243			    mode->mode);
1244			return (EINVAL);
1245		}
1246		DPRINTF(5, "\n");
1247		return 0;
1248	}
1249
1250	case VT_GETMODE:	/* get screen switcher mode */
1251		bcopy(&vw->vw_smode, data, sizeof(struct vt_mode));
1252		return 0;
1253
1254	case VT_RELDISP:	/* screen switcher ioctl */
1255		/*
1256		 * This must be the current vty which is in the VT_PROCESS
1257		 * switching mode...
1258		 */
1259		if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode !=
1260		    VT_PROCESS)) {
1261			return EINVAL;
1262		}
1263		/* ...and this process is controlling it. */
1264		if (vw->vw_proc != td->td_proc) {
1265			return EPERM;
1266		}
1267		error = EINVAL;
1268		switch(*(int *)data) {
1269		case VT_FALSE:	/* user refuses to release screen, abort */
1270			if ((error = finish_vt_rel(vw, FALSE, &s)) == 0)
1271				DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", SC_DRIVER_NAME,
1272				    VT_UNIT(vw));
1273			break;
1274		case VT_TRUE:	/* user has released screen, go on */
1275			/* finish_vt_rel(..., TRUE, ...) should not be locked */
1276			if (vw->vw_flags & VWF_SWWAIT_REL) {
1277				if ((error = finish_vt_rel(vw, TRUE, &s)) == 0)
1278					DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n",
1279					    SC_DRIVER_NAME, VT_UNIT(vw));
1280			} else {
1281				error = EINVAL;
1282			}
1283			return (error);
1284		case VT_ACKACQ:	/* acquire acknowledged, switch completed */
1285			if ((error = finish_vt_acq(vw)) == 0)
1286				DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", SC_DRIVER_NAME,
1287				    VT_UNIT(vw));
1288			break;
1289		default:
1290			break;
1291		}
1292		return error;
1293	}
1294
1295	return (ENOIOCTL);
1296}
1297
1298static struct vt_window *
1299vt_allocate_window(struct vt_device *vd, unsigned int window)
1300{
1301	struct vt_window *vw;
1302	struct terminal *tm;
1303	term_pos_t size;
1304	struct winsize wsz;
1305
1306	vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO);
1307	vw->vw_device = vd;
1308	vw->vw_number = window;
1309	vw->vw_kbdmode = K_XLATE;
1310
1311	if (!(vd->vd_flags & VDF_TEXTMODE))
1312		vw->vw_font = vtfont_ref(&vt_font_default);
1313
1314	vt_termsize(vd, vw->vw_font, &size);
1315	vt_winsize(vd, vw->vw_font, &wsz);
1316	vtbuf_init(&vw->vw_buf, &size);
1317
1318	tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw);
1319	terminal_set_winsize(tm, &wsz);
1320	vd->vd_windows[window] = vw;
1321	callout_init(&vw->vw_proc_dead_timer, 0);
1322
1323	return (vw);
1324}
1325
1326void
1327vt_upgrade(struct vt_device *vd)
1328{
1329	struct vt_window *vw;
1330	unsigned int i;
1331
1332	/* Device didn't pass vd_init() or already upgraded. */
1333	if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD))
1334		return;
1335	vd->vd_flags |= VDF_ASYNC;
1336
1337	mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF);
1338	cv_init(&vd->vd_winswitch, "vtwswt");
1339
1340	/* Init 25 Hz timer. */
1341	callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0);
1342
1343	for (i = 0; i < VT_MAXWINDOWS; i++) {
1344		vw = vd->vd_windows[i];
1345		if (vw == NULL) {
1346			/* New window. */
1347			vw = vt_allocate_window(vd, i);
1348		}
1349		if (i == VT_CONSWINDOW) {
1350			/* Console window. */
1351			EVENTHANDLER_REGISTER(shutdown_pre_sync,
1352			    vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT);
1353		}
1354		terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw));
1355	}
1356	if (vd->vd_curwindow == NULL)
1357		vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW];
1358
1359	/* Attach keyboard. */
1360	vt_allocate_keyboard(vd);
1361	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
1362
1363	/* Start timer when everything ready. */
1364	callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd);
1365}
1366
1367static void
1368vt_resize(struct vt_device *vd)
1369{
1370	struct vt_window *vw;
1371	int i;
1372
1373	for (i = 0; i < VT_MAXWINDOWS; i++) {
1374		vw = vd->vd_windows[i];
1375		/* Resize terminal windows */
1376		vt_change_font(vw, vw->vw_font);
1377	}
1378}
1379
1380void
1381vt_allocate(struct vt_driver *drv, void *softc)
1382{
1383	struct vt_device *vd;
1384
1385	if (main_vd == NULL) {
1386		main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO);
1387	} else {
1388		/*
1389		 * Check if have rights to replace current driver. For example:
1390		 * it is bad idea to replace KMS driver with generic VGA one.
1391		 */
1392		/* Lowest preferred. */
1393		if (drv->vd_priority >= main_vd->vd_driver->vd_priority)
1394			return;
1395	}
1396	vd = main_vd;
1397
1398	/* Stop vd_flash periodic task. */
1399	if (vd->vd_curwindow != NULL)
1400		callout_drain(&vd->vd_timer);
1401
1402	vd->vd_driver = drv;
1403	vd->vd_softc = softc;
1404	vd->vd_driver->vd_init(vd);
1405
1406	vt_upgrade(vd);
1407
1408	/* Refill settings with new sizes. */
1409	vt_resize(vd);
1410
1411	if (vd->vd_flags & VDF_SPLASH)
1412		vtterm_splash(vd);
1413
1414	if (vd->vd_curwindow != NULL)
1415		callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
1416
1417	termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal);
1418}
1419