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