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