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