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