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