vt_core.c revision 258023
1219888Sed/*-
2257547Sray * Copyright (c) 2009, 2013 The FreeBSD Foundation
3219888Sed * All rights reserved.
4219888Sed *
5219888Sed * This software was developed by Ed Schouten under sponsorship from the
6219888Sed * FreeBSD Foundation.
7219888Sed *
8257547Sray * Portions of this software were developed by Oleksandr Rybalko
9257547Sray * under sponsorship from the FreeBSD Foundation.
10257547Sray *
11219888Sed * Redistribution and use in source and binary forms, with or without
12219888Sed * modification, are permitted provided that the following conditions
13219888Sed * are met:
14219888Sed * 1. Redistributions of source code must retain the above copyright
15219888Sed *    notice, this list of conditions and the following disclaimer.
16219888Sed * 2. Redistributions in binary form must reproduce the above copyright
17219888Sed *    notice, this list of conditions and the following disclaimer in the
18219888Sed *    documentation and/or other materials provided with the distribution.
19219888Sed *
20219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219888Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30219888Sed * SUCH DAMAGE.
31219888Sed */
32219888Sed
33219888Sed#include <sys/cdefs.h>
34219888Sed__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/vt_core.c 258023 2013-11-11 22:07:56Z ray $");
35219888Sed
36219888Sed#include <sys/param.h>
37219888Sed#include <sys/consio.h>
38219888Sed#include <sys/eventhandler.h>
39219888Sed#include <sys/fbio.h>
40219888Sed#include <sys/kbio.h>
41219888Sed#include <sys/kdb.h>
42219888Sed#include <sys/kernel.h>
43219888Sed#include <sys/lock.h>
44219888Sed#include <sys/malloc.h>
45219888Sed#include <sys/mutex.h>
46256145Sray#include <sys/proc.h>
47219888Sed#include <sys/reboot.h>
48219888Sed#include <sys/systm.h>
49219888Sed#include <sys/terminal.h>
50219888Sed
51219888Sed#include <dev/kbd/kbdreg.h>
52219888Sed#include <dev/vt/vt.h>
53219888Sed
54219888Sedstatic tc_bell_t	vtterm_bell;
55219888Sedstatic tc_cursor_t	vtterm_cursor;
56219888Sedstatic tc_putchar_t	vtterm_putchar;
57219888Sedstatic tc_fill_t	vtterm_fill;
58219888Sedstatic tc_copy_t	vtterm_copy;
59219888Sedstatic tc_param_t	vtterm_param;
60219888Sedstatic tc_done_t	vtterm_done;
61219888Sed
62219888Sedstatic tc_cnprobe_t	vtterm_cnprobe;
63219888Sedstatic tc_cngetc_t	vtterm_cngetc;
64219888Sed
65219888Sedstatic tc_opened_t	vtterm_opened;
66219888Sedstatic tc_ioctl_t	vtterm_ioctl;
67219888Sed
68219888Sedconst struct terminal_class vt_termclass = {
69219888Sed	.tc_bell	= vtterm_bell,
70219888Sed	.tc_cursor	= vtterm_cursor,
71219888Sed	.tc_putchar	= vtterm_putchar,
72219888Sed	.tc_fill	= vtterm_fill,
73219888Sed	.tc_copy	= vtterm_copy,
74219888Sed	.tc_param	= vtterm_param,
75219888Sed	.tc_done	= vtterm_done,
76219888Sed
77219888Sed	.tc_cnprobe	= vtterm_cnprobe,
78219888Sed	.tc_cngetc	= vtterm_cngetc,
79219888Sed
80219888Sed	.tc_opened	= vtterm_opened,
81219888Sed	.tc_ioctl	= vtterm_ioctl,
82219888Sed};
83219888Sed
84219888Sed/*
85257296Snwhitehorn * Use a constant timer of 25 Hz to redraw the screen.
86219888Sed *
87219888Sed * XXX: In theory we should only fire up the timer when there is really
88219888Sed * activity. Unfortunately we cannot always start timers. We really
89219888Sed * don't want to process kernel messages synchronously, because it
90219888Sed * really slows down the system.
91219888Sed */
92257296Snwhitehorn#define	VT_TIMERFREQ	25
93219888Sed
94219888Sed/* Bell pitch/duration. */
95219888Sed#define VT_BELLDURATION	((5 * hz + 99) / 100)
96219888Sed#define VT_BELLPITCH	800
97219888Sed
98219888Sed#define	VT_LOCK(vd)	mtx_lock(&(vd)->vd_lock)
99219888Sed#define	VT_UNLOCK(vd)	mtx_unlock(&(vd)->vd_lock)
100219888Sed
101219888Sed#define	VT_UNIT(vw)	((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
102219888Sed			(vw)->vw_number)
103219888Sed
104256145Sray/* XXX while syscons is here. */
105256145Srayint sc_txtmouse_no_retrace_wait;
106256145Sray
107256145Sraystatic SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters");
108256145SrayVT_SYSCTL_INT(debug, 0, "Newcons debug level");
109256145SrayVT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
110258023SrayVT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend");
111256145Sray
112219888Sedstatic unsigned int vt_unit = 0;
113219888Sedstatic MALLOC_DEFINE(M_VT, "vt", "vt device");
114256145Sraystruct vt_device *main_vd = NULL;
115219888Sed
116219888Sed/* Boot logo. */
117219888Sedextern unsigned int vt_logo_width;
118219888Sedextern unsigned int vt_logo_height;
119219888Sedextern unsigned int vt_logo_depth;
120219888Sedextern unsigned char vt_logo_image[];
121219888Sed
122219888Sed/* Font. */
123219888Sedextern struct vt_font vt_font_default;
124257986Srayextern struct mouse_cursor vt_default_mouse_pointer;
125219888Sed
126256145Sraystatic int signal_vt_rel(struct vt_window *);
127256145Sraystatic int signal_vt_acq(struct vt_window *);
128256145Sraystatic int finish_vt_rel(struct vt_window *, int, int *);
129256145Sraystatic int finish_vt_acq(struct vt_window *);
130256145Sraystatic int vt_window_switch(struct vt_window *);
131256145Sraystatic int vt_late_window_switch(struct vt_window *);
132256145Sraystatic int vt_proc_alive(struct vt_window *);
133256145Sraystatic void vt_resize(struct vt_device *);
134256145Sray
135219888Sedstatic void
136256145Srayvt_switch_timer(void *arg)
137256145Sray{
138256145Sray
139256145Sray	vt_late_window_switch((struct vt_window *)arg);
140256145Sray}
141256145Sray
142256145Sraystatic int
143256145Srayvt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
144256145Sray{
145256145Sray
146256145Sray	DPRINTF(40, "%s\n", __func__);
147256145Sray	curvw->vw_switch_to = vw;
148256145Sray	/* Set timer to allow switch in case when process hang. */
149256145Sray	callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer,
150256145Sray	    vt_switch_timer, (void *)vw);
151256145Sray	/* Notify process about vt switch attempt. */
152256145Sray	DPRINTF(30, "%s: Notify process.\n", __func__);
153256145Sray	signal_vt_rel(curvw);
154256145Sray
155256145Sray	return (0);
156256145Sray}
157256145Sray
158256145Sraystatic int
159256145Srayvt_window_postswitch(struct vt_window *vw)
160256145Sray{
161256145Sray
162256145Sray	signal_vt_acq(vw);
163256145Sray	return (0);
164256145Sray}
165256145Sray
166256145Sray/* vt_late_window_switch will done VT switching for regular case. */
167256145Sraystatic int
168256145Srayvt_late_window_switch(struct vt_window *vw)
169256145Sray{
170256145Sray	int ret;
171256145Sray
172256145Sray	callout_stop(&vw->vw_proc_dead_timer);
173256145Sray
174256145Sray	ret = vt_window_switch(vw);
175256145Sray	if (ret)
176256145Sray		return (ret);
177256145Sray
178256145Sray	/* Notify owner process about terminal availability. */
179256145Sray	if (vw->vw_smode.mode == VT_PROCESS) {
180256145Sray		ret = vt_window_postswitch(vw);
181256145Sray	}
182256145Sray	return (ret);
183256145Sray}
184256145Sray
185256145Sray/* Switch window. */
186256145Sraystatic int
187256145Srayvt_proc_window_switch(struct vt_window *vw)
188256145Sray{
189256145Sray	struct vt_window *curvw;
190256145Sray	struct vt_device *vd;
191256145Sray	int ret;
192256145Sray
193256145Sray	if (vw->vw_flags & VWF_VTYLOCK)
194256145Sray		return (EBUSY);
195256145Sray
196256145Sray	vd = vw->vw_device;
197256145Sray	curvw = vd->vd_curwindow;
198256145Sray
199256145Sray	/* Ask current process permitions to switch away. */
200256145Sray	if (curvw->vw_smode.mode == VT_PROCESS) {
201256145Sray		DPRINTF(30, "%s: VT_PROCESS ", __func__);
202256145Sray		if (vt_proc_alive(curvw) == FALSE) {
203256145Sray			DPRINTF(30, "Dead. Cleaning.");
204256145Sray			/* Dead */
205256145Sray		} else {
206256145Sray			DPRINTF(30, "%s: Signaling process.\n", __func__);
207256145Sray			/* Alive, try to ask him. */
208256145Sray			ret = vt_window_preswitch(vw, curvw);
209256145Sray			/* Wait for process answer or timeout. */
210256145Sray			return (ret);
211256145Sray		}
212256145Sray		DPRINTF(30, "\n");
213256145Sray	}
214256145Sray
215256145Sray	ret = vt_late_window_switch(vw);
216256145Sray	return (ret);
217256145Sray}
218256145Sray
219256145Sray/* Switch window ignoring process locking. */
220256145Sraystatic int
221219888Sedvt_window_switch(struct vt_window *vw)
222219888Sed{
223219888Sed	struct vt_device *vd = vw->vw_device;
224256145Sray	struct vt_window *curvw = vd->vd_curwindow;
225219888Sed	keyboard_t *kbd;
226219888Sed
227219888Sed	VT_LOCK(vd);
228256145Sray	if (curvw == vw) {
229256145Sray		/* Nothing to do. */
230219888Sed		VT_UNLOCK(vd);
231256145Sray		return (0);
232219888Sed	}
233256145Sray	if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
234256145Sray		VT_UNLOCK(vd);
235256145Sray		return (EINVAL);
236256145Sray	}
237256145Sray
238219888Sed	vd->vd_curwindow = vw;
239219888Sed	vd->vd_flags |= VDF_INVALID;
240219888Sed	cv_broadcast(&vd->vd_winswitch);
241219888Sed	VT_UNLOCK(vd);
242219888Sed
243256145Sray	if (vd->vd_driver->vd_postswitch)
244256145Sray		vd->vd_driver->vd_postswitch(vd);
245256145Sray
246219888Sed	/* Restore per-window keyboard mode. */
247219888Sed	mtx_lock(&Giant);
248219888Sed	kbd = kbd_get_keyboard(vd->vd_keyboard);
249256145Sray	if (kbd != NULL) {
250219888Sed		kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode);
251256145Sray	}
252219888Sed	mtx_unlock(&Giant);
253256145Sray	DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
254256145Sray
255256145Sray	return (0);
256219888Sed}
257219888Sed
258219888Sedstatic inline void
259219888Sedvt_termsize(struct vt_device *vd, struct vt_font *vf, term_pos_t *size)
260219888Sed{
261219888Sed
262219888Sed	size->tp_row = vd->vd_height;
263219888Sed	size->tp_col = vd->vd_width;
264219888Sed	if (vf != NULL) {
265219888Sed		size->tp_row /= vf->vf_height;
266219888Sed		size->tp_col /= vf->vf_width;
267219888Sed	}
268219888Sed}
269219888Sed
270219888Sedstatic inline void
271219888Sedvt_winsize(struct vt_device *vd, struct vt_font *vf, struct winsize *size)
272219888Sed{
273219888Sed
274219888Sed	size->ws_row = size->ws_ypixel = vd->vd_height;
275219888Sed	size->ws_col = size->ws_xpixel = vd->vd_width;
276219888Sed	if (vf != NULL) {
277219888Sed		size->ws_row /= vf->vf_height;
278219888Sed		size->ws_col /= vf->vf_width;
279219888Sed	}
280219888Sed}
281219888Sed
282257076Sraystatic void
283257076Srayvt_scroll(struct vt_window *vw, int offset, int whence)
284257076Sray{
285257076Sray	int diff;
286257076Sray	term_pos_t size;
287257076Sray
288257076Sray	if ((vw->vw_flags & VWF_SCROLL) == 0)
289257076Sray		return;
290257076Sray
291257076Sray	vt_termsize(vw->vw_device, vw->vw_font, &size);
292257076Sray
293257076Sray	diff = vthistory_seek(&vw->vw_buf, offset, whence);
294257076Sray	/*
295257076Sray	 * Offset changed, please update Nth lines on sceen.
296257076Sray	 * +N - Nth lines at top;
297257076Sray	 * -N - Nth lines at bottom.
298257076Sray	 */
299257076Sray
300257076Sray	if (diff < -size.tp_row || diff > size.tp_row) {
301257076Sray		vw->vw_device->vd_flags |= VDF_INVALID;
302257076Sray		return;
303257076Sray	}
304257076Sray	vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/
305257076Sray}
306257076Sray
307219888Sedstatic int
308257076Srayvt_machine_kbdevent(int c)
309257076Sray{
310257076Sray
311257076Sray	switch (c) {
312257076Sray	case SPCLKEY | DBG:
313257076Sray		kdb_enter(KDB_WHY_BREAK, "manual escape to debugger");
314257076Sray		return (1);
315257076Sray	case SPCLKEY | RBT:
316257076Sray		/* XXX: Make this configurable! */
317257076Sray		shutdown_nice(0);
318257076Sray		return (1);
319257076Sray	case SPCLKEY | HALT:
320257076Sray		shutdown_nice(RB_HALT);
321257076Sray		return (1);
322257076Sray	case SPCLKEY | PDWN:
323257076Sray		shutdown_nice(RB_HALT|RB_POWEROFF);
324257076Sray		return (1);
325257076Sray	};
326257076Sray
327257076Sray	return (0);
328257076Sray}
329257076Sray
330257076Sraystatic void
331257076Srayvt_scrollmode_kbdevent(struct vt_window *vw, int c, int console)
332257076Sray{
333257076Sray	struct vt_device *vd;
334257076Sray	term_pos_t size;
335257076Sray
336257076Sray	vd = vw->vw_device;
337257076Sray	/* Only special keys handled in ScrollLock mode */
338257076Sray	if ((c & SPCLKEY) == 0)
339257076Sray		return;
340257076Sray
341257076Sray	c &= ~SPCLKEY;
342257076Sray
343257076Sray	if (console == 0) {
344257076Sray		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
345257076Sray			vw = vd->vd_windows[c - F_SCR];
346257076Sray			if (vw != NULL)
347257076Sray				vt_proc_window_switch(vw);
348257076Sray			return;
349257076Sray		}
350257076Sray		VT_LOCK(vd);
351257076Sray	}
352257076Sray
353257076Sray	switch (c) {
354257076Sray	case SLK: {
355257076Sray		/* Turn scrolling off. */
356257076Sray		vt_scroll(vw, 0, VHS_END);
357257076Sray		VTBUF_SLCK_DISABLE(&vw->vw_buf);
358257076Sray		vw->vw_flags &= ~VWF_SCROLL;
359257076Sray		break;
360257076Sray	}
361257076Sray	case FKEY | F(49): /* Home key. */
362257076Sray		vt_scroll(vw, 0, VHS_END);
363257076Sray		break;
364257076Sray	case FKEY | F(50): /* Arrow up. */
365257076Sray		vt_scroll(vw, -1, VHS_CUR);
366257076Sray		break;
367257076Sray	case FKEY | F(51): /* Page up. */
368257076Sray		vt_termsize(vd, vw->vw_font, &size);
369257076Sray		vt_scroll(vw, -size.tp_row, VHS_CUR);
370257076Sray		break;
371257076Sray	case FKEY | F(57): /* End key. */
372257076Sray		vt_scroll(vw, 0, VHS_SET);
373257076Sray		break;
374257076Sray	case FKEY | F(58): /* Arrow down. */
375257076Sray		vt_scroll(vw, 1, VHS_CUR);
376257076Sray		break;
377257076Sray	case FKEY | F(59): /* Page down. */
378257076Sray		vt_termsize(vd, vw->vw_font, &size);
379257076Sray		vt_scroll(vw, size.tp_row, VHS_CUR);
380257076Sray		break;
381257076Sray	}
382257076Sray
383257076Sray	if (console == 0)
384257076Sray		VT_UNLOCK(vd);
385257076Sray}
386257076Sray
387257076Sraystatic int
388257294Snwhitehornvt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
389219888Sed{
390219888Sed	struct vt_window *vw = vd->vd_curwindow;
391257294Snwhitehorn	int state = 0;
392219888Sed
393219888Sed	if (c & RELKEY)
394219888Sed		return (0);
395219888Sed
396257076Sray	if (vt_machine_kbdevent(c))
397257076Sray		return (0);
398257076Sray
399257076Sray	if (vw->vw_flags & VWF_SCROLL) {
400257076Sray		vt_scrollmode_kbdevent(vw, c, 0/* Not a console */);
401257076Sray		/* Scroll mode keys handled, nothing to do more. */
402257076Sray		return (0);
403257076Sray	}
404257076Sray
405219888Sed	if (c & SPCLKEY) {
406219888Sed		c &= ~SPCLKEY;
407219888Sed
408219888Sed		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
409219888Sed			vw = vd->vd_windows[c - F_SCR];
410219888Sed			if (vw != NULL)
411256145Sray				vt_proc_window_switch(vw);
412219888Sed			return (0);
413219888Sed		}
414219888Sed
415219888Sed		switch (c) {
416219888Sed		case SLK: {
417219888Sed
418219888Sed			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
419219888Sed			VT_LOCK(vd);
420219888Sed			if (state & SLKED) {
421219888Sed				/* Turn scrolling on. */
422219888Sed				vw->vw_flags |= VWF_SCROLL;
423256145Sray				VTBUF_SLCK_ENABLE(&vw->vw_buf);
424219888Sed			} else {
425219888Sed				/* Turn scrolling off. */
426219888Sed				vw->vw_flags &= ~VWF_SCROLL;
427256145Sray				VTBUF_SLCK_DISABLE(&vw->vw_buf);
428257076Sray				vt_scroll(vw, 0, VHS_END);
429219888Sed			}
430219888Sed			VT_UNLOCK(vd);
431219888Sed			break;
432219888Sed		}
433219888Sed		case FKEY | F(1):  case FKEY | F(2):  case FKEY | F(3):
434219888Sed		case FKEY | F(4):  case FKEY | F(5):  case FKEY | F(6):
435219888Sed		case FKEY | F(7):  case FKEY | F(8):  case FKEY | F(9):
436219888Sed		case FKEY | F(10): case FKEY | F(11): case FKEY | F(12):
437219888Sed			/* F1 through F12 keys. */
438219888Sed			terminal_input_special(vw->vw_terminal,
439219888Sed			    TKEY_F1 + c - (FKEY | F(1)));
440219888Sed			break;
441219888Sed		case FKEY | F(49): /* Home key. */
442219888Sed			terminal_input_special(vw->vw_terminal, TKEY_HOME);
443219888Sed			break;
444219888Sed		case FKEY | F(50): /* Arrow up. */
445219888Sed			terminal_input_special(vw->vw_terminal, TKEY_UP);
446219888Sed			break;
447219888Sed		case FKEY | F(51): /* Page up. */
448219888Sed			terminal_input_special(vw->vw_terminal, TKEY_PAGE_UP);
449219888Sed			break;
450219888Sed		case FKEY | F(53): /* Arrow left. */
451219888Sed			terminal_input_special(vw->vw_terminal, TKEY_LEFT);
452219888Sed			break;
453219888Sed		case FKEY | F(55): /* Arrow right. */
454219888Sed			terminal_input_special(vw->vw_terminal, TKEY_RIGHT);
455219888Sed			break;
456219888Sed		case FKEY | F(57): /* End key. */
457219888Sed			terminal_input_special(vw->vw_terminal, TKEY_END);
458219888Sed			break;
459219888Sed		case FKEY | F(58): /* Arrow down. */
460219888Sed			terminal_input_special(vw->vw_terminal, TKEY_DOWN);
461219888Sed			break;
462219888Sed		case FKEY | F(59): /* Page down. */
463219888Sed			terminal_input_special(vw->vw_terminal, TKEY_PAGE_DOWN);
464219888Sed			break;
465219888Sed		case FKEY | F(60): /* Insert key. */
466219888Sed			terminal_input_special(vw->vw_terminal, TKEY_INSERT);
467219888Sed			break;
468219888Sed		case FKEY | F(61): /* Delete key. */
469219888Sed			terminal_input_special(vw->vw_terminal, TKEY_DELETE);
470219888Sed			break;
471219888Sed		}
472219888Sed	} else if (KEYFLAGS(c) == 0) {
473219888Sed		/* Don't do UTF-8 conversion when doing raw mode. */
474219888Sed		if (vw->vw_kbdmode == K_XLATE)
475256145Sray			terminal_input_char(vw->vw_terminal, KEYCHAR(c));
476219888Sed		else
477219888Sed			terminal_input_raw(vw->vw_terminal, c);
478219888Sed	}
479219888Sed	return (0);
480219888Sed}
481219888Sed
482219888Sedstatic int
483257294Snwhitehornvt_kbdevent(keyboard_t *kbd, int event, void *arg)
484257294Snwhitehorn{
485257294Snwhitehorn	struct vt_device *vd = arg;
486257294Snwhitehorn	int c;
487257294Snwhitehorn
488257294Snwhitehorn	switch (event) {
489257294Snwhitehorn	case KBDIO_KEYINPUT:
490257294Snwhitehorn		break;
491257294Snwhitehorn	case KBDIO_UNLOADING:
492257294Snwhitehorn		mtx_lock(&Giant);
493257294Snwhitehorn		vd->vd_keyboard = -1;
494257294Snwhitehorn		kbd_release(kbd, (void *)&vd->vd_keyboard);
495257294Snwhitehorn		mtx_unlock(&Giant);
496257294Snwhitehorn		return (0);
497257294Snwhitehorn	default:
498257294Snwhitehorn		return (EINVAL);
499257294Snwhitehorn	}
500257294Snwhitehorn
501257294Snwhitehorn	while ((c = kbdd_read_char(kbd, 0)) != NOKEY)
502257294Snwhitehorn		vt_processkey(kbd, vd, c);
503257294Snwhitehorn
504257294Snwhitehorn	return (0);
505257294Snwhitehorn}
506257294Snwhitehorn
507257294Snwhitehornstatic int
508219888Sedvt_allocate_keyboard(struct vt_device *vd)
509219888Sed{
510219888Sed	int		 idx0, idx;
511219888Sed	keyboard_t	*k0, *k;
512219888Sed	keyboard_info_t	 ki;
513219888Sed
514219888Sed	idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard,
515219888Sed	    vt_kbdevent, vd);
516256145Sray	/* XXX: kb_token lost */
517256145Sray	vd->vd_keyboard = idx0;
518219888Sed	if (idx0 != -1) {
519256145Sray		DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
520219888Sed		k0 = kbd_get_keyboard(idx0);
521219888Sed
522219888Sed		for (idx = kbd_find_keyboard2("*", -1, 0);
523219888Sed		     idx != -1;
524219888Sed		     idx = kbd_find_keyboard2("*", -1, idx + 1)) {
525219888Sed			k = kbd_get_keyboard(idx);
526219888Sed
527219888Sed			if (idx == idx0 || KBD_IS_BUSY(k))
528219888Sed				continue;
529219888Sed
530219888Sed			bzero(&ki, sizeof(ki));
531219888Sed			strcpy(ki.kb_name, k->kb_name);
532219888Sed			ki.kb_unit = k->kb_unit;
533219888Sed
534219888Sed			kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
535219888Sed		}
536256145Sray	} else {
537256145Sray		DPRINTF(20, "%s: no kbdmux allocated\n", __func__);
538219888Sed		idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard,
539219888Sed		    vt_kbdevent, vd);
540256145Sray	}
541256145Sray	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
542219888Sed
543219888Sed	return (idx0);
544219888Sed}
545219888Sed
546219888Sedstatic void
547219888Sedvtterm_bell(struct terminal *tm)
548219888Sed{
549219888Sed
550219888Sed	sysbeep(1193182 / VT_BELLPITCH, VT_BELLDURATION);
551219888Sed}
552219888Sed
553219888Sedstatic void
554219888Sedvtterm_cursor(struct terminal *tm, const term_pos_t *p)
555219888Sed{
556219888Sed	struct vt_window *vw = tm->tm_softc;
557219888Sed
558219888Sed	vtbuf_cursor_position(&vw->vw_buf, p);
559219888Sed}
560219888Sed
561219888Sedstatic void
562219888Sedvtterm_putchar(struct terminal *tm, const term_pos_t *p, term_char_t c)
563219888Sed{
564219888Sed	struct vt_window *vw = tm->tm_softc;
565219888Sed
566219888Sed	vtbuf_putchar(&vw->vw_buf, p, c);
567219888Sed}
568219888Sed
569219888Sedstatic void
570219888Sedvtterm_fill(struct terminal *tm, const term_rect_t *r, term_char_t c)
571219888Sed{
572219888Sed	struct vt_window *vw = tm->tm_softc;
573219888Sed
574256145Sray	vtbuf_fill_locked(&vw->vw_buf, r, c);
575219888Sed}
576219888Sed
577219888Sedstatic void
578219888Sedvtterm_copy(struct terminal *tm, const term_rect_t *r,
579219888Sed    const term_pos_t *p)
580219888Sed{
581219888Sed	struct vt_window *vw = tm->tm_softc;
582219888Sed
583219888Sed	vtbuf_copy(&vw->vw_buf, r, p);
584219888Sed}
585219888Sed
586219888Sedstatic void
587219888Sedvtterm_param(struct terminal *tm, int cmd, unsigned int arg)
588219888Sed{
589219888Sed	struct vt_window *vw = tm->tm_softc;
590219888Sed
591219888Sed	switch (cmd) {
592219888Sed	case TP_SHOWCURSOR:
593219888Sed		vtbuf_cursor_visibility(&vw->vw_buf, arg);
594219888Sed		break;
595219888Sed	}
596219888Sed}
597219888Sed
598219888Sedstatic inline void
599219888Sedvt_determine_colors(term_char_t c, int cursor,
600219888Sed    term_color_t *fg, term_color_t *bg)
601219888Sed{
602219888Sed
603219888Sed	*fg = TCHAR_FGCOLOR(c);
604219888Sed	if (TCHAR_FORMAT(c) & TF_BOLD)
605219888Sed		*fg = TCOLOR_LIGHT(*fg);
606219888Sed	*bg = TCHAR_BGCOLOR(c);
607219888Sed
608219888Sed	if (TCHAR_FORMAT(c) & TF_REVERSE) {
609219888Sed		term_color_t tmp;
610219888Sed
611219888Sed		tmp = *fg;
612219888Sed		*fg = *bg;
613219888Sed		*bg = tmp;
614219888Sed	}
615219888Sed
616219888Sed	if (cursor) {
617219888Sed		*fg = *bg;
618219888Sed		*bg = TC_WHITE;
619219888Sed	}
620219888Sed}
621219888Sed
622219888Sedstatic void
623219888Sedvt_bitblt_char(struct vt_device *vd, struct vt_font *vf, term_char_t c,
624219888Sed    int iscursor, unsigned int row, unsigned int col)
625219888Sed{
626219888Sed	term_color_t fg, bg;
627219888Sed
628219888Sed	vt_determine_colors(c, iscursor, &fg, &bg);
629219888Sed
630219888Sed	if (vf != NULL) {
631219888Sed		const uint8_t *src;
632219888Sed		vt_axis_t top, left;
633219888Sed
634219888Sed		src = vtfont_lookup(vf, c);
635219888Sed
636219888Sed		/*
637219888Sed		 * Align the terminal to the centre of the screen.
638219888Sed		 * Fonts may not always be able to fill the entire
639219888Sed		 * screen.
640219888Sed		 */
641257979Sray		top = row * vf->vf_height + vd->vd_offset.tp_row;
642257979Sray		left = col * vf->vf_width + vd->vd_offset.tp_col;
643219888Sed
644257988Sray		vd->vd_driver->vd_bitbltchr(vd, src, NULL, 0, top, left,
645219888Sed		    vf->vf_width, vf->vf_height, fg, bg);
646219888Sed	} else {
647219888Sed		vd->vd_driver->vd_putchar(vd, TCHAR_CHARACTER(c),
648219888Sed		    row, col, fg, bg);
649219888Sed	}
650219888Sed}
651219888Sed
652219888Sedstatic void
653219888Sedvt_flush(struct vt_device *vd)
654219888Sed{
655219888Sed	struct vt_window *vw = vd->vd_curwindow;
656219888Sed	struct vt_font *vf = vw->vw_font;
657219888Sed	struct vt_bufmask tmask;
658257981Sray	struct mouse_cursor *m;
659256145Sray	unsigned int row, col;
660257981Sray	term_rect_t tarea;
661257981Sray	term_pos_t size;
662256145Sray	term_char_t *r;
663257988Sray	int bpl, h, w;
664219888Sed
665219888Sed	if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
666219888Sed		return;
667219888Sed
668219888Sed	vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
669219888Sed	vt_termsize(vd, vf, &size);
670219888Sed
671219888Sed	/* Force a full redraw when the screen contents are invalid. */
672256145Sray	if (vd->vd_flags & VDF_INVALID) {
673219888Sed		tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0;
674219888Sed		tarea.tr_end = size;
675219888Sed		tmask.vbm_row = tmask.vbm_col = VBM_DIRTY;
676219888Sed
677219888Sed		vd->vd_flags &= ~VDF_INVALID;
678219888Sed	}
679219888Sed
680257981Sray	/* No mouse for DDB. */
681257981Sray	if (kdb_active || panicstr != NULL)
682257981Sray		return;
683219888Sed
684257981Sray	/* Mark last mouse position as dirty to erase. */
685257981Sray	vtbuf_mouse_cursor_position(&vw->vw_buf, vd->vd_mdirtyx, vd->vd_mdirtyy);
686257981Sray
687219888Sed	for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) {
688219888Sed		if (!VTBUF_DIRTYROW(&tmask, row))
689219888Sed			continue;
690256145Sray		r = VTBUF_GET_ROW(&vw->vw_buf, row);
691219888Sed		for (col = tarea.tr_begin.tp_col;
692219888Sed		    col < tarea.tr_end.tp_col; col++) {
693219888Sed			if (!VTBUF_DIRTYCOL(&tmask, col))
694219888Sed				continue;
695219888Sed
696256145Sray			vt_bitblt_char(vd, vf, r[col],
697256903Sray			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), row, col);
698219888Sed		}
699219888Sed	}
700257981Sray
701257981Sray	if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) ==
702257981Sray	    VDF_MOUSECURSOR) {
703257981Sray		m = &vt_default_mouse_pointer;
704257988Sray		bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */
705257981Sray		w = m->w;
706257981Sray		h = m->h;
707257981Sray
708257981Sray		if ((vd->vd_mx + m->w) > (size.tp_col * vf->vf_width))
709257981Sray			w = (size.tp_col * vf->vf_width) - vd->vd_mx - 1;
710257981Sray		if ((vd->vd_my + m->h) > (size.tp_row * vf->vf_height))
711257981Sray			h = (size.tp_row * vf->vf_height) - vd->vd_my - 1;
712257981Sray
713257988Sray		vd->vd_driver->vd_bitbltchr(vd, m->map, m->mask, bpl,
714257981Sray		    vd->vd_offset.tp_row + vd->vd_my,
715257981Sray		    vd->vd_offset.tp_col + vd->vd_mx,
716257981Sray		    w, h, TC_WHITE, TC_BLACK);
717257981Sray		/* Save point of last mouse cursor to erase it later. */
718257981Sray		vd->vd_mdirtyx = vd->vd_mx / vf->vf_width;
719257981Sray		vd->vd_mdirtyy = vd->vd_my / vf->vf_height;
720257981Sray	}
721219888Sed}
722219888Sed
723219888Sedstatic void
724219888Sedvt_timer(void *arg)
725219888Sed{
726257387Sray	struct vt_device *vd;
727219888Sed
728257387Sray	vd = arg;
729257387Sray	/* Update screen if required. */
730219888Sed	vt_flush(vd);
731257387Sray	/* Schedule for next update. */
732219888Sed	callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
733219888Sed}
734219888Sed
735219888Sedstatic void
736219888Sedvtterm_done(struct terminal *tm)
737219888Sed{
738219888Sed	struct vt_window *vw = tm->tm_softc;
739219888Sed	struct vt_device *vd = vw->vw_device;
740219888Sed
741219888Sed	if (kdb_active || panicstr != NULL) {
742219888Sed		/* Switch to the debugger. */
743219888Sed		if (vd->vd_curwindow != vw) {
744219888Sed			vd->vd_curwindow = vw;
745219888Sed			vd->vd_flags |= VDF_INVALID;
746257626Sray			if (vd->vd_driver->vd_postswitch)
747257626Sray				vd->vd_driver->vd_postswitch(vd);
748219888Sed		}
749219888Sed		vd->vd_flags &= ~VDF_SPLASH;
750219888Sed		vt_flush(vd);
751219888Sed	} else if (!(vd->vd_flags & VDF_ASYNC)) {
752219888Sed		vt_flush(vd);
753219888Sed	}
754219888Sed}
755219888Sed
756219888Sedstatic void
757256145Srayvtterm_splash(struct vt_device *vd)
758256145Sray{
759256145Sray	vt_axis_t top, left;
760256145Sray
761256145Sray	/* Display a nice boot splash. */
762257722Sray	if (!(vd->vd_flags & VDF_TEXTMODE) && (boothowto & RB_MUTE)) {
763256145Sray
764256145Sray		top = (vd->vd_height - vt_logo_height) / 2;
765256145Sray		left = (vd->vd_width - vt_logo_width) / 2;
766256145Sray		switch (vt_logo_depth) {
767256145Sray		case 1:
768256145Sray			/* XXX: Unhardcode colors! */
769257988Sray			vd->vd_driver->vd_bitbltchr(vd, vt_logo_image, NULL, 0,
770257988Sray			    top, left, vt_logo_width, vt_logo_height, 0xf, 0x0);
771256145Sray		}
772256145Sray		vd->vd_flags |= VDF_SPLASH;
773256145Sray	}
774256145Sray}
775256145Sray
776256145Sraystatic void
777219888Sedvtterm_cnprobe(struct terminal *tm, struct consdev *cp)
778219888Sed{
779219888Sed	struct vt_window *vw = tm->tm_softc;
780219888Sed	struct vt_device *vd = vw->vw_device;
781219888Sed	struct winsize wsz;
782219888Sed
783256145Sray	if (vd->vd_flags & VDF_INITIALIZED)
784256145Sray		/* Initialization already done. */
785256145Sray		return;
786256145Sray
787219888Sed	cp->cn_pri = vd->vd_driver->vd_init(vd);
788219888Sed	if (cp->cn_pri == CN_DEAD) {
789219888Sed		vd->vd_flags |= VDF_DEAD;
790219888Sed		return;
791219888Sed	}
792219888Sed
793230469Snwhitehorn	/* Initialize any early-boot keyboard drivers */
794230469Snwhitehorn	kbd_configure(KB_CONF_PROBE_ONLY);
795230469Snwhitehorn
796219888Sed	vd->vd_unit = atomic_fetchadd_int(&vt_unit, 1);
797256145Sray	vd->vd_windows[VT_CONSWINDOW] = vw;
798219888Sed	sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw));
799219888Sed
800219888Sed	if (!(vd->vd_flags & VDF_TEXTMODE))
801219888Sed		vw->vw_font = vtfont_ref(&vt_font_default);
802219888Sed
803219888Sed	vtbuf_init_early(&vw->vw_buf);
804219888Sed	vt_winsize(vd, vw->vw_font, &wsz);
805219888Sed	terminal_set_winsize(tm, &wsz);
806219888Sed
807256145Sray	vtterm_splash(vd);
808219888Sed
809256145Sray	vd->vd_flags |= VDF_INITIALIZED;
810256145Sray	main_vd = vd;
811219888Sed}
812219888Sed
813219888Sedstatic int
814219888Sedvtterm_cngetc(struct terminal *tm)
815219888Sed{
816219888Sed	struct vt_window *vw = tm->tm_softc;
817219888Sed	struct vt_device *vd = vw->vw_device;
818219888Sed	keyboard_t *kbd;
819257076Sray	int state;
820219888Sed	u_int c;
821219888Sed
822257076Sray	if (vw->vw_kbdsq && *vw->vw_kbdsq)
823257076Sray		return (*vw->vw_kbdsq++);
824257076Sray
825257076Sray	state = 0;
826219888Sed	/* Make sure the splash screen is not there. */
827219888Sed	if (vd->vd_flags & VDF_SPLASH) {
828256145Sray		/* Remove splash */
829219888Sed		vd->vd_flags &= ~VDF_SPLASH;
830256145Sray		/* Mark screen as invalid to force update */
831256145Sray		vd->vd_flags |= VDF_INVALID;
832219888Sed		vt_flush(vd);
833219888Sed	}
834219888Sed
835219888Sed	/* Stripped down keyboard handler. */
836219888Sed	kbd = kbd_get_keyboard(vd->vd_keyboard);
837219888Sed	if (kbd == NULL)
838219888Sed		return (-1);
839219888Sed
840256145Sray	/* Force keyboard input mode to K_XLATE */
841256145Sray	c = K_XLATE;
842256145Sray	kbdd_ioctl(kbd, KDSKBMODE, (void *)&c);
843256145Sray
844219888Sed	/* Switch the keyboard to polling to make it work here. */
845219888Sed	kbdd_poll(kbd, TRUE);
846219888Sed	c = kbdd_read_char(kbd, 0);
847219888Sed	kbdd_poll(kbd, FALSE);
848219888Sed	if (c & RELKEY)
849219888Sed		return (-1);
850256145Sray
851257076Sray	if (vw->vw_flags & VWF_SCROLL) {
852257076Sray		vt_scrollmode_kbdevent(vw, c, 1/* Console mode */);
853257076Sray		vt_flush(vd);
854257076Sray		return (-1);
855257076Sray	}
856257076Sray
857219888Sed	/* Stripped down handling of vt_kbdevent(), without locking, etc. */
858219888Sed	if (c & SPCLKEY) {
859219888Sed		switch (c) {
860257076Sray		case SPCLKEY | SLK:
861219888Sed			kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
862219888Sed			if (state & SLKED) {
863219888Sed				/* Turn scrolling on. */
864219888Sed				vw->vw_flags |= VWF_SCROLL;
865256145Sray				VTBUF_SLCK_ENABLE(&vw->vw_buf);
866219888Sed			} else {
867219888Sed				/* Turn scrolling off. */
868257076Sray				vt_scroll(vw, 0, VHS_END);
869219888Sed				vw->vw_flags &= ~VWF_SCROLL;
870256145Sray				VTBUF_SLCK_DISABLE(&vw->vw_buf);
871219888Sed			}
872219888Sed			break;
873257076Sray		/* XXX: KDB can handle history. */
874257076Sray		case SPCLKEY | FKEY | F(50): /* Arrow up. */
875257076Sray			vw->vw_kbdsq = "\x1b[A";
876219888Sed			break;
877257076Sray		case SPCLKEY | FKEY | F(58): /* Arrow down. */
878257076Sray			vw->vw_kbdsq = "\x1b[B";
879219888Sed			break;
880257076Sray		case SPCLKEY | FKEY | F(55): /* Arrow right. */
881257076Sray			vw->vw_kbdsq = "\x1b[C";
882219888Sed			break;
883257076Sray		case SPCLKEY | FKEY | F(53): /* Arrow left. */
884257076Sray			vw->vw_kbdsq = "\x1b[D";
885219888Sed			break;
886219888Sed		}
887219888Sed
888219888Sed		/* Force refresh to make scrollback work. */
889219888Sed		vt_flush(vd);
890219888Sed	} else if (KEYFLAGS(c) == 0) {
891219888Sed		return KEYCHAR(c);
892219888Sed	}
893256145Sray
894257076Sray	if (vw->vw_kbdsq && *vw->vw_kbdsq)
895257076Sray		return (*
896257076Sray		vw->vw_kbdsq++);
897257076Sray
898219888Sed	return (-1);
899219888Sed}
900219888Sed
901219888Sedstatic void
902219888Sedvtterm_opened(struct terminal *tm, int opened)
903219888Sed{
904219888Sed	struct vt_window *vw = tm->tm_softc;
905219888Sed	struct vt_device *vd = vw->vw_device;
906219888Sed
907219888Sed	VT_LOCK(vd);
908219888Sed	vd->vd_flags &= ~VDF_SPLASH;
909219888Sed	if (opened)
910219888Sed		vw->vw_flags |= VWF_OPENED;
911256145Sray	else {
912219888Sed		vw->vw_flags &= ~VWF_OPENED;
913256145Sray		/* TODO: finish ACQ/REL */
914256145Sray	}
915219888Sed	VT_UNLOCK(vd);
916219888Sed}
917219888Sed
918219888Sedstatic int
919219888Sedvt_change_font(struct vt_window *vw, struct vt_font *vf)
920219888Sed{
921219888Sed	struct vt_device *vd = vw->vw_device;
922219888Sed	struct terminal *tm = vw->vw_terminal;
923219888Sed	term_pos_t size;
924219888Sed	struct winsize wsz;
925219888Sed
926219888Sed	/*
927219888Sed	 * Changing fonts.
928219888Sed	 *
929219888Sed	 * Changing fonts is a little tricky.  We must prevent
930219888Sed	 * simultaneous access to the device, so we must stop
931219888Sed	 * the display timer and the terminal from accessing.
932219888Sed	 * We need to switch fonts and grow our screen buffer.
933219888Sed	 *
934219888Sed	 * XXX: Right now the code uses terminal_mute() to
935219888Sed	 * prevent data from reaching the console driver while
936219888Sed	 * resizing the screen buffer.  This isn't elegant...
937219888Sed	 */
938219888Sed
939219888Sed	VT_LOCK(vd);
940219888Sed	if (vw->vw_flags & VWF_BUSY) {
941219888Sed		/* Another process is changing the font. */
942219888Sed		VT_UNLOCK(vd);
943219888Sed		return (EBUSY);
944219888Sed	}
945219888Sed	if (vw->vw_font == NULL) {
946219888Sed		/* Our device doesn't need fonts. */
947219888Sed		VT_UNLOCK(vd);
948219888Sed		return (ENOTTY);
949219888Sed	}
950219888Sed	vw->vw_flags |= VWF_BUSY;
951219888Sed	VT_UNLOCK(vd);
952219888Sed
953219888Sed	vt_termsize(vd, vf, &size);
954219888Sed	vt_winsize(vd, vf, &wsz);
955257978Sray	/* Save offset to font aligned area. */
956257978Sray	vd->vd_offset.tp_col = (vd->vd_width % vf->vf_width) / 2;
957257978Sray	vd->vd_offset.tp_row = (vd->vd_height % vf->vf_height) / 2;
958219888Sed
959219888Sed	/* Grow the screen buffer and terminal. */
960219888Sed	terminal_mute(tm, 1);
961256145Sray	vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
962256903Sray	terminal_set_winsize_blank(tm, &wsz, 0);
963219888Sed	terminal_mute(tm, 0);
964219888Sed
965219888Sed	/* Actually apply the font to the current window. */
966219888Sed	VT_LOCK(vd);
967219888Sed	vtfont_unref(vw->vw_font);
968219888Sed	vw->vw_font = vtfont_ref(vf);
969219888Sed
970219888Sed	/* Force a full redraw the next timer tick. */
971219888Sed	if (vd->vd_curwindow == vw)
972219888Sed		vd->vd_flags |= VDF_INVALID;
973219888Sed	vw->vw_flags &= ~VWF_BUSY;
974219888Sed	VT_UNLOCK(vd);
975219888Sed	return (0);
976219888Sed}
977219888Sed
978219888Sedstatic int
979256145Srayvt_proc_alive(struct vt_window *vw)
980256145Sray{
981256145Sray	struct proc *p;
982256145Sray
983256145Sray	if (vw->vw_smode.mode != VT_PROCESS)
984256145Sray		return FALSE;
985256145Sray
986256145Sray	if (vw->vw_proc) {
987256145Sray		if ((p = pfind(vw->vw_pid)) != NULL)
988256145Sray			PROC_UNLOCK(p);
989256145Sray		if (vw->vw_proc == p)
990256145Sray			return TRUE;
991256145Sray		vw->vw_proc = NULL;
992256145Sray		vw->vw_smode.mode = VT_AUTO;
993256145Sray		DPRINTF(1, "vt controlling process %d died\n", vw->vw_pid);
994256145Sray		vw->vw_pid = 0;
995256145Sray	}
996256145Sray	return FALSE;
997256145Sray}
998256145Sray
999256145Sraystatic int
1000256145Sraysignal_vt_rel(struct vt_window *vw)
1001256145Sray{
1002257815Sray
1003256145Sray	if (vw->vw_smode.mode != VT_PROCESS)
1004256145Sray		return FALSE;
1005256145Sray	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
1006256145Sray		vw->vw_proc = NULL;
1007256145Sray		vw->vw_pid = 0;
1008256145Sray		return TRUE;
1009256145Sray	}
1010256145Sray	vw->vw_flags |= VWF_SWWAIT_REL;
1011256145Sray	PROC_LOCK(vw->vw_proc);
1012256145Sray	kern_psignal(vw->vw_proc, vw->vw_smode.relsig);
1013256145Sray	PROC_UNLOCK(vw->vw_proc);
1014256145Sray	DPRINTF(1, "sending relsig to %d\n", vw->vw_pid);
1015256145Sray	return TRUE;
1016256145Sray}
1017256145Sray
1018256145Sraystatic int
1019256145Sraysignal_vt_acq(struct vt_window *vw)
1020256145Sray{
1021257815Sray
1022256145Sray	if (vw->vw_smode.mode != VT_PROCESS)
1023256145Sray		return FALSE;
1024256145Sray	if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1025256145Sray		cnavailable(vw->vw_terminal->consdev, FALSE);
1026256145Sray	if (vw->vw_proc == NULL || vt_proc_alive(vw) == FALSE) {
1027256145Sray		vw->vw_proc = NULL;
1028256145Sray		vw->vw_pid = 0;
1029256145Sray		return TRUE;
1030256145Sray	}
1031256145Sray	vw->vw_flags |= VWF_SWWAIT_ACQ;
1032256145Sray	PROC_LOCK(vw->vw_proc);
1033256145Sray	kern_psignal(vw->vw_proc, vw->vw_smode.acqsig);
1034256145Sray	PROC_UNLOCK(vw->vw_proc);
1035256145Sray	DPRINTF(1, "sending acqsig to %d\n", vw->vw_pid);
1036256145Sray	return TRUE;
1037256145Sray}
1038256145Sray
1039256145Sraystatic int
1040256145Srayfinish_vt_rel(struct vt_window *vw, int release, int *s)
1041256145Sray{
1042257815Sray
1043256145Sray	if (vw->vw_flags & VWF_SWWAIT_REL) {
1044256145Sray		vw->vw_flags &= ~VWF_SWWAIT_REL;
1045256145Sray		if (release) {
1046256145Sray			callout_drain(&vw->vw_proc_dead_timer);
1047256145Sray			vt_late_window_switch(vw->vw_switch_to);
1048256145Sray		}
1049256145Sray		return 0;
1050256145Sray	}
1051256145Sray	return EINVAL;
1052256145Sray}
1053256145Sray
1054256145Sraystatic int
1055256145Srayfinish_vt_acq(struct vt_window *vw)
1056256145Sray{
1057257815Sray
1058256145Sray	if (vw->vw_flags & VWF_SWWAIT_ACQ) {
1059256145Sray		vw->vw_flags &= ~VWF_SWWAIT_ACQ;
1060256145Sray		return 0;
1061256145Sray	}
1062256145Sray	return EINVAL;
1063256145Sray}
1064256145Sray
1065257977Srayvoid
1066257977Srayvt_mouse_event(int type, int x, int y, int event, int cnt)
1067257977Sray{
1068257977Sray	struct vt_device *vd;
1069257977Sray	struct vt_window *vw;
1070257977Sray	struct vt_font *vf;
1071257977Sray	term_pos_t size;
1072257977Sray	int mark;
1073257977Sray
1074257977Sray	vd = main_vd;
1075257977Sray	vw = vd->vd_curwindow;
1076257977Sray	vf = vw->vw_font;
1077257977Sray
1078257977Sray	if (vf == NULL)	/* Text mode. */
1079257977Sray		return;
1080257977Sray
1081257977Sray	/*
1082257977Sray	 * TODO: add flag about pointer position changed, to not redraw chars
1083257977Sray	 * under mouse pointer when nothing changed.
1084257977Sray	 */
1085257977Sray
1086257977Sray	switch (type) {
1087257977Sray	case MOUSE_ACTION:
1088257977Sray	case MOUSE_MOTION_EVENT:
1089257977Sray		/* Movement */
1090257977Sray		x += vd->vd_mx;
1091257977Sray		y += vd->vd_my;
1092257977Sray
1093257977Sray		vt_termsize(vd, vf, &size);
1094257977Sray
1095257977Sray		/* Apply limits. */
1096257977Sray		x = MAX(x, 0);
1097257977Sray		y = MAX(y, 0);
1098257977Sray		x = MIN(x, (size.tp_col * vf->vf_width) - 1);
1099257977Sray		y = MIN(y, (size.tp_row * vf->vf_height) - 1);
1100257977Sray
1101257977Sray		vd->vd_mx = x;
1102257977Sray		vd->vd_my = y;
1103257977Sray		if (vd->vd_mstate & MOUSE_BUTTON1DOWN)
1104257977Sray			vtbuf_set_mark(&vw->vw_buf, VTB_MARK_END,
1105257977Sray			    vd->vd_mx / vf->vf_width,
1106257977Sray			    vd->vd_my / vf->vf_height);
1107257977Sray		return; /* Done */
1108257977Sray	case MOUSE_BUTTON_EVENT:
1109257977Sray		/* Buttons */
1110257977Sray		break;
1111257977Sray	default:
1112257977Sray		return; /* Done */
1113257977Sray	}
1114257977Sray
1115257977Sray	switch (event) {
1116257977Sray	case MOUSE_BUTTON1DOWN:
1117257977Sray		switch (cnt % 4) {
1118257977Sray		case 0:	/* up */
1119257977Sray			mark = VTB_MARK_END;
1120257977Sray			break;
1121257977Sray		case 1: /* single click: start cut operation */
1122257977Sray			mark = VTB_MARK_START;
1123257977Sray			break;
1124257977Sray		case 2:	/* double click: cut a word */
1125257977Sray			mark = VTB_MARK_WORD;
1126257977Sray			break;
1127257977Sray		case 3:	/* triple click: cut a line */
1128257977Sray			mark = VTB_MARK_ROW;
1129257977Sray			break;
1130257977Sray		}
1131257977Sray		break;
1132257977Sray	case VT_MOUSE_PASTEBUTTON:
1133257977Sray		switch (event) {
1134257977Sray		case 0:	/* up */
1135257977Sray			break;
1136257977Sray		default:
1137257977Sray			//sc_mouse_paste(cur_scp);
1138257977Sray			break;
1139257977Sray		}
1140257977Sray		return; /* Done */
1141257977Sray	case VT_MOUSE_EXTENDBUTTON:
1142257977Sray		switch (event) {
1143257977Sray		case 0:	/* up */
1144257977Sray			if (!(vd->vd_mstate & MOUSE_BUTTON1DOWN))
1145257977Sray				mark = VTB_MARK_END;
1146257977Sray			else
1147257977Sray				mark = 0;
1148257977Sray			break;
1149257977Sray		default:
1150257977Sray			mark = VTB_MARK_EXTEND;
1151257977Sray			break;
1152257977Sray		}
1153257977Sray		break;
1154257977Sray	default:
1155257977Sray		return; /* Done */
1156257977Sray	}
1157257977Sray
1158257977Sray	/* Save buttons state. */
1159257977Sray	if (cnt > 0)
1160257977Sray		vd->vd_mstate |= event;
1161257977Sray	else
1162257977Sray		vd->vd_mstate &= ~event;
1163257977Sray
1164257977Sray	vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width,
1165257977Sray	    vd->vd_my / vf->vf_height);
1166257977Sray}
1167257977Sray
1168256145Sraystatic int
1169219888Sedvtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
1170219888Sed    struct thread *td)
1171219888Sed{
1172219888Sed	struct vt_window *vw = tm->tm_softc;
1173219888Sed	struct vt_device *vd = vw->vw_device;
1174256145Sray	int error, s;
1175219888Sed
1176219888Sed	switch (cmd) {
1177219888Sed	case GIO_KEYMAP:
1178219888Sed	case PIO_KEYMAP:
1179219888Sed	case GIO_DEADKEYMAP:
1180219888Sed	case PIO_DEADKEYMAP:
1181219888Sed	case GETFKEY:
1182219888Sed	case SETFKEY:
1183219888Sed	case KDGKBINFO: {
1184219888Sed		keyboard_t *kbd;
1185256145Sray		error = 0;
1186219888Sed
1187219888Sed		mtx_lock(&Giant);
1188219888Sed		kbd = kbd_get_keyboard(vd->vd_keyboard);
1189219888Sed		if (kbd != NULL)
1190219888Sed			error = kbdd_ioctl(kbd, cmd, data);
1191219888Sed		mtx_unlock(&Giant);
1192219888Sed		if (error == ENOIOCTL)
1193219888Sed			return (ENODEV);
1194219888Sed		return (error);
1195219888Sed	}
1196256145Sray	case KDGKBMODE: {
1197256145Sray		int mode = -1;
1198256145Sray		keyboard_t *kbd;
1199256145Sray
1200256145Sray		mtx_lock(&Giant);
1201256145Sray		kbd = kbd_get_keyboard(vd->vd_keyboard);
1202256145Sray		if (kbd != NULL) {
1203256145Sray			kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode);
1204256145Sray		}
1205256145Sray		mtx_unlock(&Giant);
1206256145Sray		DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode);
1207256145Sray		*(int *)data = mode;
1208256145Sray		return (0);
1209256145Sray	}
1210219888Sed	case KDSKBMODE: {
1211219888Sed		int mode;
1212219888Sed
1213219888Sed		mode = *(int *)data;
1214219888Sed		switch (mode) {
1215219888Sed		case K_XLATE:
1216219888Sed		case K_RAW:
1217219888Sed		case K_CODE:
1218219888Sed			vw->vw_kbdmode = mode;
1219219888Sed			if (vw == vd->vd_curwindow) {
1220219888Sed				keyboard_t *kbd;
1221256145Sray				error = 0;
1222219888Sed
1223257983Sray				DPRINTF(20, "%s: vd_keyboard = %d\n", __func__,
1224257983Sray				    vd->vd_keyboard);
1225219888Sed				mtx_lock(&Giant);
1226219888Sed				kbd = kbd_get_keyboard(vd->vd_keyboard);
1227256145Sray				if (kbd != NULL) {
1228256145Sray					DPRINTF(20, "kbdd_ioctl(KDSKBMODE, %d)\n", mode);
1229256145Sray					error = kbdd_ioctl(kbd, KDSKBMODE,
1230219888Sed					    (void *)&mode);
1231256145Sray				}
1232219888Sed				mtx_unlock(&Giant);
1233256145Sray				if (error)
1234257983Sray					DPRINTF(20, "kbdd_ioctl(KDSKBMODE) "
1235257983Sray					    "return %d\n", error);
1236219888Sed			}
1237219888Sed			return (0);
1238219888Sed		default:
1239219888Sed			return (EINVAL);
1240219888Sed		}
1241219888Sed	}
1242219888Sed	case CONS_BLANKTIME:
1243219888Sed		/* XXX */
1244219888Sed		return (0);
1245219888Sed	case CONS_GET:
1246219888Sed		/* XXX */
1247219888Sed		*(int *)data = M_CG640x480;
1248219888Sed		return (0);
1249219888Sed	case CONS_GETINFO: {
1250219888Sed		vid_info_t *vi = (vid_info_t *)data;
1251219888Sed
1252219888Sed		vi->m_num = vd->vd_curwindow->vw_number + 1;
1253219888Sed		/* XXX: other fields! */
1254219888Sed		return (0);
1255219888Sed	}
1256219888Sed	case CONS_GETVERS:
1257219888Sed		*(int *)data = 0x200;
1258219888Sed		return 0;
1259219888Sed	case CONS_MODEINFO:
1260219888Sed		/* XXX */
1261219888Sed		return (0);
1262219888Sed	case CONS_MOUSECTL: {
1263219888Sed		mouse_info_t *mouse = (mouse_info_t*)data;
1264219888Sed
1265219888Sed		/*
1266219888Sed		 * This has no effect on vt(4).  We don't draw any mouse
1267219888Sed		 * cursor.  Just ignore MOUSE_HIDE and MOUSE_SHOW to
1268219888Sed		 * prevent excessive errors.  All the other commands
1269219888Sed		 * should not be applied to individual TTYs, but only to
1270219888Sed		 * consolectl.
1271219888Sed		 */
1272219888Sed		switch (mouse->operation) {
1273219888Sed		case MOUSE_HIDE:
1274257982Sray			vd->vd_flags &= ~VDF_MOUSECURSOR;
1275257982Sray			return (0);
1276219888Sed		case MOUSE_SHOW:
1277257982Sray			vd->vd_mx = vd->vd_width / 2;
1278257982Sray			vd->vd_my = vd->vd_height / 2;
1279257982Sray			vd->vd_flags |= VDF_MOUSECURSOR;
1280219888Sed			return (0);
1281219888Sed		default:
1282219888Sed			return (EINVAL);
1283219888Sed		}
1284219888Sed	}
1285219888Sed	case PIO_VFONT: {
1286219888Sed		struct vt_font *vf;
1287219888Sed
1288219888Sed		error = vtfont_load((void *)data, &vf);
1289219888Sed		if (error != 0)
1290219888Sed			return (error);
1291219888Sed
1292219888Sed		error = vt_change_font(vw, vf);
1293219888Sed		vtfont_unref(vf);
1294219888Sed		return (error);
1295219888Sed	}
1296219888Sed	case GIO_SCRNMAP: {
1297219888Sed		scrmap_t *sm = (scrmap_t *)data;
1298219888Sed		int i;
1299219888Sed
1300219888Sed		/* We don't have screen maps, so return a handcrafted one. */
1301219888Sed		for (i = 0; i < 256; i++)
1302219888Sed			sm->scrmap[i] = i;
1303219888Sed		return (0);
1304219888Sed	}
1305219888Sed	case KDGETLED:
1306219888Sed		/* XXX */
1307219888Sed		return (0);
1308219888Sed	case KDSETLED:
1309219888Sed		/* XXX */
1310219888Sed		return (0);
1311219888Sed	case KDSETMODE:
1312219888Sed		/* XXX */
1313219888Sed		return (0);
1314219888Sed	case KDSETRAD:
1315219888Sed		/* XXX */
1316219888Sed		return (0);
1317256145Sray	case VT_ACTIVATE: {
1318256145Sray		int win;
1319256145Sray		win = *(int *)data - 1;
1320256145Sray		DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME, VT_UNIT(vw), win);
1321256145Sray		if ((win > VT_MAXWINDOWS) || (win < 0))
1322256145Sray			return (EINVAL);
1323256145Sray		return (vt_proc_window_switch(vd->vd_windows[win]));
1324256145Sray	}
1325219888Sed	case VT_GETACTIVE:
1326219888Sed		*(int *)data = vd->vd_curwindow->vw_number + 1;
1327219888Sed		return (0);
1328219888Sed	case VT_GETINDEX:
1329219888Sed		*(int *)data = vw->vw_number + 1;
1330219888Sed		return (0);
1331256145Sray	case VT_LOCKSWITCH:
1332256145Sray		/* TODO: Check current state, switching can be in progress. */
1333256145Sray		if ((*(int *)data) & 0x01)
1334256145Sray			vw->vw_flags |= VWF_VTYLOCK;
1335256145Sray		else
1336256145Sray			vw->vw_flags &= ~VWF_VTYLOCK;
1337219888Sed	case VT_OPENQRY: {
1338219888Sed		unsigned int i;
1339219888Sed
1340219888Sed		VT_LOCK(vd);
1341219888Sed		for (i = 0; i < VT_MAXWINDOWS; i++) {
1342219888Sed			vw = vd->vd_windows[i];
1343219888Sed			if (vw == NULL)
1344219888Sed				continue;
1345219888Sed			if (!(vw->vw_flags & VWF_OPENED)) {
1346219888Sed				*(int *)data = vw->vw_number + 1;
1347219888Sed				VT_UNLOCK(vd);
1348219888Sed				return (0);
1349219888Sed			}
1350219888Sed		}
1351219888Sed		VT_UNLOCK(vd);
1352219888Sed		return (EINVAL);
1353219888Sed	}
1354219888Sed	case VT_WAITACTIVE: {
1355219888Sed		unsigned int i;
1356256145Sray		error = 0;
1357219888Sed
1358219888Sed		i = *(unsigned int *)data;
1359219888Sed		if (i > VT_MAXWINDOWS)
1360219888Sed			return (EINVAL);
1361219888Sed		if (i != 0)
1362219888Sed			vw = vd->vd_windows[i - 1];
1363219888Sed
1364219888Sed		VT_LOCK(vd);
1365219888Sed		while (vd->vd_curwindow != vw && error == 0)
1366219888Sed			error = cv_wait_sig(&vd->vd_winswitch, &vd->vd_lock);
1367219888Sed		VT_UNLOCK(vd);
1368219888Sed		return (error);
1369219888Sed	}
1370256145Sray	case VT_SETMODE:    	/* set screen switcher mode */
1371256145Sray	{
1372256145Sray		struct vt_mode *mode;
1373256145Sray		struct proc *p1;
1374256145Sray
1375256145Sray		mode = (struct vt_mode *)data;
1376256145Sray		DPRINTF(5, "%s%d: VT_SETMODE ", SC_DRIVER_NAME, VT_UNIT(vw));
1377256145Sray		if (vw->vw_smode.mode == VT_PROCESS) {
1378256145Sray			p1 = pfind(vw->vw_pid);
1379256145Sray			if (vw->vw_proc == p1 && vw->vw_proc != td->td_proc) {
1380256145Sray				if (p1)
1381256145Sray					PROC_UNLOCK(p1);
1382256145Sray				DPRINTF(5, "error EPERM\n");
1383256145Sray				return (EPERM);
1384256145Sray			}
1385256145Sray			if (p1)
1386256145Sray				PROC_UNLOCK(p1);
1387256145Sray		}
1388256145Sray		if (mode->mode == VT_AUTO) {
1389256145Sray			vw->vw_smode.mode = VT_AUTO;
1390256145Sray			vw->vw_proc = NULL;
1391256145Sray			vw->vw_pid = 0;
1392256145Sray			DPRINTF(5, "VT_AUTO, ");
1393256145Sray			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1394256145Sray				cnavailable(vw->vw_terminal->consdev, TRUE);
1395256145Sray			/* were we in the middle of the vty switching process? */
1396256145Sray			if (finish_vt_rel(vw, TRUE, &s) == 0)
1397256145Sray				DPRINTF(5, "reset WAIT_REL, ");
1398256145Sray			if (finish_vt_acq(vw) == 0)
1399256145Sray				DPRINTF(5, "reset WAIT_ACQ, ");
1400256145Sray			return (0);
1401256145Sray		} else if (mode->mode == VT_PROCESS) {
1402256145Sray			if (!ISSIGVALID(mode->relsig) ||
1403256145Sray			    !ISSIGVALID(mode->acqsig) ||
1404256145Sray			    !ISSIGVALID(mode->frsig)) {
1405256145Sray				DPRINTF(5, "error EINVAL\n");
1406256145Sray				return (EINVAL);
1407256145Sray			}
1408256145Sray			DPRINTF(5, "VT_PROCESS %d, ", td->td_proc->p_pid);
1409256145Sray			bcopy(data, &vw->vw_smode, sizeof(struct vt_mode));
1410256145Sray			vw->vw_proc = td->td_proc;
1411256145Sray			vw->vw_pid = vw->vw_proc->p_pid;
1412256145Sray			if (vw == vw->vw_device->vd_windows[VT_CONSWINDOW])
1413256145Sray				cnavailable(vw->vw_terminal->consdev, FALSE);
1414256145Sray		} else {
1415256145Sray			DPRINTF(5, "VT_SETMODE failed, unknown mode %d\n",
1416256145Sray			    mode->mode);
1417256145Sray			return (EINVAL);
1418256145Sray		}
1419256145Sray		DPRINTF(5, "\n");
1420256145Sray		return 0;
1421219888Sed	}
1422219888Sed
1423256145Sray	case VT_GETMODE:	/* get screen switcher mode */
1424256145Sray		bcopy(&vw->vw_smode, data, sizeof(struct vt_mode));
1425256145Sray		return 0;
1426256145Sray
1427256145Sray	case VT_RELDISP:	/* screen switcher ioctl */
1428256145Sray		/*
1429256145Sray		 * This must be the current vty which is in the VT_PROCESS
1430256145Sray		 * switching mode...
1431256145Sray		 */
1432256145Sray		if ((vw != vd->vd_curwindow) || (vw->vw_smode.mode !=
1433256145Sray		    VT_PROCESS)) {
1434256145Sray			return EINVAL;
1435256145Sray		}
1436256145Sray		/* ...and this process is controlling it. */
1437256145Sray		if (vw->vw_proc != td->td_proc) {
1438256145Sray			return EPERM;
1439256145Sray		}
1440256145Sray		error = EINVAL;
1441256145Sray		switch(*(int *)data) {
1442256145Sray		case VT_FALSE:	/* user refuses to release screen, abort */
1443256145Sray			if ((error = finish_vt_rel(vw, FALSE, &s)) == 0)
1444256145Sray				DPRINTF(5, "%s%d: VT_RELDISP: VT_FALSE\n", SC_DRIVER_NAME,
1445256145Sray				    VT_UNIT(vw));
1446256145Sray			break;
1447256145Sray		case VT_TRUE:	/* user has released screen, go on */
1448256145Sray			/* finish_vt_rel(..., TRUE, ...) should not be locked */
1449256145Sray			if (vw->vw_flags & VWF_SWWAIT_REL) {
1450256145Sray				if ((error = finish_vt_rel(vw, TRUE, &s)) == 0)
1451256145Sray					DPRINTF(5, "%s%d: VT_RELDISP: VT_TRUE\n",
1452256145Sray					    SC_DRIVER_NAME, VT_UNIT(vw));
1453256145Sray			} else {
1454256145Sray				error = EINVAL;
1455256145Sray			}
1456256145Sray			return (error);
1457256145Sray		case VT_ACKACQ:	/* acquire acknowledged, switch completed */
1458256145Sray			if ((error = finish_vt_acq(vw)) == 0)
1459256145Sray				DPRINTF(5, "%s%d: VT_RELDISP: VT_ACKACQ\n", SC_DRIVER_NAME,
1460256145Sray				    VT_UNIT(vw));
1461256145Sray			break;
1462256145Sray		default:
1463256145Sray			break;
1464256145Sray		}
1465256145Sray		return error;
1466256145Sray	}
1467256145Sray
1468219888Sed	return (ENOIOCTL);
1469219888Sed}
1470219888Sed
1471219888Sedstatic struct vt_window *
1472219888Sedvt_allocate_window(struct vt_device *vd, unsigned int window)
1473219888Sed{
1474219888Sed	struct vt_window *vw;
1475219888Sed	struct terminal *tm;
1476219888Sed	term_pos_t size;
1477219888Sed	struct winsize wsz;
1478219888Sed
1479219888Sed	vw = malloc(sizeof *vw, M_VT, M_WAITOK|M_ZERO);
1480219888Sed	vw->vw_device = vd;
1481219888Sed	vw->vw_number = window;
1482219888Sed	vw->vw_kbdmode = K_XLATE;
1483219888Sed
1484219888Sed	if (!(vd->vd_flags & VDF_TEXTMODE))
1485219888Sed		vw->vw_font = vtfont_ref(&vt_font_default);
1486256145Sray
1487219888Sed	vt_termsize(vd, vw->vw_font, &size);
1488219888Sed	vt_winsize(vd, vw->vw_font, &wsz);
1489219888Sed	vtbuf_init(&vw->vw_buf, &size);
1490219888Sed
1491219888Sed	tm = vw->vw_terminal = terminal_alloc(&vt_termclass, vw);
1492219888Sed	terminal_set_winsize(tm, &wsz);
1493219888Sed	vd->vd_windows[window] = vw;
1494256145Sray	callout_init(&vw->vw_proc_dead_timer, 0);
1495219888Sed
1496219888Sed	return (vw);
1497219888Sed}
1498219888Sed
1499219888Sedvoid
1500219888Sedvt_upgrade(struct vt_device *vd)
1501219888Sed{
1502219888Sed	struct vt_window *vw;
1503219888Sed	unsigned int i;
1504219888Sed
1505256145Sray	/* Device didn't pass vd_init() or already upgraded. */
1506256145Sray	if (vd->vd_flags & (VDF_ASYNC|VDF_DEAD))
1507219888Sed		return;
1508256145Sray	vd->vd_flags |= VDF_ASYNC;
1509219888Sed
1510219888Sed	mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF);
1511219888Sed	cv_init(&vd->vd_winswitch, "vtwswt");
1512219888Sed
1513256145Sray	/* Init 25 Hz timer. */
1514219888Sed	callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0);
1515219888Sed
1516219888Sed	for (i = 0; i < VT_MAXWINDOWS; i++) {
1517219888Sed		vw = vd->vd_windows[i];
1518219888Sed		if (vw == NULL) {
1519219888Sed			/* New window. */
1520219888Sed			vw = vt_allocate_window(vd, i);
1521256145Sray		}
1522256145Sray		if (i == VT_CONSWINDOW) {
1523219888Sed			/* Console window. */
1524219888Sed			EVENTHANDLER_REGISTER(shutdown_pre_sync,
1525219888Sed			    vt_window_switch, vw, SHUTDOWN_PRI_DEFAULT);
1526219888Sed		}
1527219888Sed		terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw));
1528219888Sed	}
1529256145Sray	if (vd->vd_curwindow == NULL)
1530256145Sray		vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW];
1531219888Sed
1532219888Sed	/* Attach keyboard. */
1533219888Sed	vt_allocate_keyboard(vd);
1534256145Sray	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
1535256145Sray
1536256145Sray	/* Start timer when everything ready. */
1537256145Sray	callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd);
1538219888Sed}
1539219888Sed
1540256145Sraystatic void
1541256145Srayvt_resize(struct vt_device *vd)
1542256145Sray{
1543256145Sray	struct vt_window *vw;
1544256145Sray	int i;
1545256145Sray
1546256145Sray	for (i = 0; i < VT_MAXWINDOWS; i++) {
1547256145Sray		vw = vd->vd_windows[i];
1548256145Sray		/* Resize terminal windows */
1549256145Sray		vt_change_font(vw, vw->vw_font);
1550256145Sray	}
1551256145Sray}
1552256145Sray
1553219888Sedvoid
1554219888Sedvt_allocate(struct vt_driver *drv, void *softc)
1555219888Sed{
1556219888Sed	struct vt_device *vd;
1557256903Sray	struct winsize wsz;
1558219888Sed
1559256145Sray	if (main_vd == NULL) {
1560256145Sray		main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO);
1561256903Sray		printf("%s: VT initialize with new VT driver.\n", __func__);
1562256145Sray	} else {
1563256145Sray		/*
1564256145Sray		 * Check if have rights to replace current driver. For example:
1565256145Sray		 * it is bad idea to replace KMS driver with generic VGA one.
1566256145Sray		 */
1567256903Sray		if (drv->vd_priority <= main_vd->vd_driver->vd_priority) {
1568256903Sray			printf("%s: Driver priority %d too low. Current %d\n ",
1569256903Sray			    __func__, drv->vd_priority,
1570256903Sray			    main_vd->vd_driver->vd_priority);
1571256145Sray			return;
1572256903Sray		}
1573256903Sray		printf("%s: Replace existing VT driver.\n", __func__);
1574256145Sray	}
1575256145Sray	vd = main_vd;
1576256145Sray
1577256527Sray	/* Stop vt_flush periodic task. */
1578256145Sray	if (vd->vd_curwindow != NULL)
1579256145Sray		callout_drain(&vd->vd_timer);
1580256145Sray
1581219888Sed	vd->vd_driver = drv;
1582219888Sed	vd->vd_softc = softc;
1583219888Sed	vd->vd_driver->vd_init(vd);
1584256145Sray
1585219888Sed	vt_upgrade(vd);
1586256145Sray
1587256145Sray	/* Refill settings with new sizes. */
1588256145Sray	vt_resize(vd);
1589256145Sray
1590256145Sray	if (vd->vd_flags & VDF_SPLASH)
1591256145Sray		vtterm_splash(vd);
1592256145Sray
1593256145Sray	if (vd->vd_curwindow != NULL)
1594256145Sray		callout_schedule(&vd->vd_timer, hz / VT_TIMERFREQ);
1595256145Sray
1596256145Sray	termcn_cnregister(vd->vd_windows[VT_CONSWINDOW]->vw_terminal);
1597256903Sray
1598256903Sray	/* Update console window sizes to actual. */
1599256903Sray	vt_winsize(vd, vd->vd_windows[VT_CONSWINDOW]->vw_font, &wsz);
1600256903Sray	terminal_set_winsize(vd->vd_windows[VT_CONSWINDOW]->vw_terminal, &wsz);
1601219888Sed}
1602257815Sray
1603257815Srayvoid
1604257815Srayvt_suspend()
1605257815Sray{
1606257815Sray
1607258023Sray	if (vt_suspendswitch == 0)
1608258023Sray		return;
1609257815Sray	/* Save current window. */
1610257815Sray	main_vd->vd_savedwindow = main_vd->vd_curwindow;
1611257815Sray	/* Ask holding process to free window and switch to console window */
1612257815Sray	vt_proc_window_switch(main_vd->vd_windows[VT_CONSWINDOW]);
1613257815Sray}
1614257815Sray
1615257815Srayvoid
1616257815Srayvt_resume()
1617257815Sray{
1618257815Sray
1619258023Sray	if (vt_suspendswitch == 0)
1620258023Sray		return;
1621257815Sray	/* Switch back to saved window */
1622257815Sray	if (main_vd->vd_savedwindow != NULL)
1623257815Sray		vt_proc_window_switch(main_vd->vd_savedwindow);
1624257815Sray	main_vd->vd_savedwindow = NULL;
1625257815Sray}
1626