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