dma - Update documentation
[dragonfly.git] / sys / dev / misc / syscons / syscons.c
CommitLineData
984263bc 1/*-
cd29885a 2 * Copyright (c) 1992-1998 Søren Schmidt
984263bc
MD
3 * All rights reserved.
4 *
2a85d763
MD
5 * This code is derived from software contributed to The DragonFly Project
6 * by Sascha Wildner <saw@online.de>
7 *
219917ca
SW
8 * Simple font scaling code by Sascha Wildner and Matthew Dillon
9 *
984263bc
MD
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer,
15 * without modification, immediately at the beginning of the file.
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 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
2123da6d 33 * $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/dev/syscons/syscons.c,v 1.336.2.17 2004/03/25 08:41:09 ru Exp $
984263bc
MD
34 */
35
1f2de5d4 36#include "use_splash.h"
984263bc
MD
37#include "opt_syscons.h"
38#include "opt_ddb.h"
984263bc
MD
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/eventhandler.h>
43#include <sys/reboot.h>
44#include <sys/conf.h>
45#include <sys/proc.h>
895c1f85 46#include <sys/priv.h>
984263bc
MD
47#include <sys/signalvar.h>
48#include <sys/sysctl.h>
ba409a88 49#include <sys/taskqueue.h>
984263bc 50#include <sys/tty.h>
937ccd40 51#include <sys/ttydefaults.h> /* for TTYDEF_* */
984263bc 52#include <sys/kernel.h>
984263bc
MD
53#include <sys/cons.h>
54#include <sys/random.h>
6dfdabab 55#include <ddb/ddb.h>
82d1ed25 56
6bc31f17 57#include <sys/thread2.h>
bd1cd9c2 58#include <sys/mutex2.h>
984263bc
MD
59
60#include <machine/clock.h>
61#include <machine/console.h>
62#include <machine/psl.h>
63#include <machine/pc/display.h>
984263bc 64#include <machine/frame.h>
233d54ad 65#include <machine/framebuffer.h>
984263bc 66
1f2de5d4
MD
67#include <dev/misc/kbd/kbdreg.h>
68#include <dev/video/fb/fbreg.h>
69#include <dev/video/fb/splashreg.h>
70#include "syscons.h"
984263bc
MD
71
72#define COLD 0
73#define WARM 1
74
75#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
76#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
77
7ae6dbf0
MD
78#define SCRN_ASYNCOK 0x0001
79#define SCRN_BULKUNLOCK 0x0002
80
984263bc 81#define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */
f6ce8b19
AHJ
82#define WANT_UNLOCK(m) do { \
83 if (m) \
84 syscons_unlock(); \
85} while (0)
86
87#define WANT_LOCK(m) do { \
88 if (m) \
89 syscons_lock(); \
90} while(0)
91
984263bc 92
b721b9ee
SW
93MALLOC_DEFINE(M_SYSCONS, "syscons", "Syscons");
94
984263bc
MD
95typedef struct default_attr {
96 int std_color; /* normal hardware color */
97 int rev_color; /* reverse hardware color */
98} default_attr;
99
100static default_attr user_default = {
101 SC_NORM_ATTR,
102 SC_NORM_REV_ATTR,
103};
104
105static default_attr kernel_default = {
106 SC_KERNEL_CONS_ATTR,
107 SC_KERNEL_CONS_REV_ATTR,
108};
109
110static int sc_console_unit = -1;
111static scr_stat *sc_console;
112static struct tty *sc_console_tty;
113static void *kernel_console_ts;
114
115static char init_done = COLD;
116static char shutdown_in_progress = FALSE;
117static char sc_malloc = FALSE;
88af68e6 118static char sc_filled_border = FALSE; /* filled initial VT border */
984263bc
MD
119
120static int saver_mode = CONS_NO_SAVER; /* LKM/user saver */
121static int run_scrn_saver = FALSE; /* should run the saver? */
122static long scrn_blank_time = 0; /* screen saver timeout value */
123#if NSPLASH > 0
124static int scrn_blanked; /* # of blanked screen */
125static int sticky_splash = FALSE;
126
127static void none_saver(sc_softc_t *sc, int blank) { }
128static void (*current_saver)(sc_softc_t *, int) = none_saver;
129#endif
130
ba409a88
IV
131/*
132 * Lock for asynchronous screen update thread, needed to safely modify the
133 * framebuffer information.
134 */
135static struct lock sc_asynctd_lk;
136
984263bc
MD
137#if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
138#include "font.h"
139#endif
140
984263bc
MD
141static bios_values_t bios_value;
142
143static int enable_panic_key;
144SYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key,
fb610fa2 145 0, "Enable the panic key (CTRL-ALT-SHIFT-ESC)");
65d694e8 146static int syscons_async;
b2208254
MD
147SYSCTL_INT(_kern, OID_AUTO, syscons_async, CTLFLAG_RW, &syscons_async,
148 0, "Asynchronous bulk syscons fb updates");
984263bc 149
ff1a8594
IV
150static int desired_cols = 0;
151TUNABLE_INT("kern.kms_columns", &desired_cols);
152
984263bc
MD
153#define SC_CONSOLECTL 255
154
59306b36
MD
155#define VIRTUAL_TTY(sc, x) ((SC_DEV((sc),(x)) != NULL) ? \
156 (SC_DEV((sc),(x))->si_tty) : NULL)
984263bc
MD
157#define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
158
cd29885a
MD
159static int debugger;
160static cdev_t cctl_dev;
bd1cd9c2
MD
161static timeout_t blink_screen_callout;
162static void sc_blink_screen(scr_stat *scp);
cabfc9f6 163static struct mtx syscons_mtx = MTX_INITIALIZER("syscons");
72da38a0 164static struct lock syscons_blink_lk = LOCK_INITIALIZER("sblnk", 0, 0);
984263bc
MD
165
166/* prototypes */
167static int scvidprobe(int unit, int flags, int cons);
168static int sckbdprobe(int unit, int flags, int cons);
169static void scmeminit(void *arg);
b13267a5 170static int scdevtounit(cdev_t dev);
984263bc
MD
171static kbd_callback_func_t sckbdevent;
172static int scparam(struct tty *tp, struct termios *t);
173static void scstart(struct tty *tp);
174static void scinit(int unit, int flags);
fb3cf125 175#if 0
984263bc 176static void scterm(int unit, int flags);
fb3cf125 177#endif
984263bc 178static void scshutdown(void *arg, int howto);
82d1ed25 179static void sc_puts(scr_stat *scp, u_char *buf, int len);
984263bc
MD
180static u_int scgetc(sc_softc_t *sc, u_int flags);
181#define SCGETC_CN 1
182#define SCGETC_NONBLOCK 2
183static int sccngetch(int flags);
184static void sccnupdate(scr_stat *scp);
185static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
186static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
187static timeout_t scrn_timer;
188static int and_region(int *s1, int *e1, int s2, int e2);
7ae6dbf0
MD
189static void scrn_update(scr_stat *scp, int show_cursor, int flags);
190static void scrn_update_thread(void *arg);
984263bc 191
ba409a88 192static void sc_fb_set_par(void *context, int pending);
f8b03d86
IV
193#if NSPLASH > 0
194static void sc_fb_blank(void *context, int pending);
195#endif /* NSPLASH */
ba409a88 196
984263bc 197#if NSPLASH > 0
f8b03d86 198static void scframebuffer_saver(sc_softc_t *sc, int show);
984263bc
MD
199static int scsplash_callback(int event, void *arg);
200static void scsplash_saver(sc_softc_t *sc, int show);
201static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
202static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
203static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
204static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
205static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
0510b0ee 206static int wait_scrn_saver_stop(sc_softc_t *sc, int need_unlock);
984263bc
MD
207#define scsplash_stick(stick) (sticky_splash = (stick))
208#else /* !NSPLASH */
209#define scsplash_stick(stick)
210#endif /* NSPLASH */
211
6bc31f17 212static void do_switch_scr(sc_softc_t *sc);
984263bc
MD
213static int vt_proc_alive(scr_stat *scp);
214static int signal_vt_rel(scr_stat *scp);
215static int signal_vt_acq(scr_stat *scp);
6bc31f17 216static int finish_vt_rel(scr_stat *scp, int release);
984263bc
MD
217static int finish_vt_acq(scr_stat *scp);
218static void exchange_scr(sc_softc_t *sc);
219static void update_cursor_image(scr_stat *scp);
f6ce8b19
AHJ
220static int save_kbd_state(scr_stat *scp, int unlock);
221static int update_kbd_state(scr_stat *scp, int state, int mask, int unlock);
984263bc 222static int update_kbd_leds(scr_stat *scp, int which);
bcc53404 223static int sc_allocate_keyboard(sc_softc_t *sc, int unit);
984263bc 224
82d1ed25 225/*
bd1cd9c2
MD
226 * Console locking support functions.
227 *
228 * We use mutex spinlocks here in order to allow reentrancy which should
532503f5 229 * avoid issues during panics.
539fbd92
MD
230 *
231 * A panic can stop a cpu while it is holding the syscons_mtx. If this
232 * occurs we try for up to 1/2 a second and then blow the spinlock away.
233 * The asynchronous update thread makes this happen more often.
82d1ed25
MD
234 */
235static void
236syscons_lock(void)
237{
539fbd92
MD
238 if (panicstr || shutdown_in_progress) {
239 int retries = 500000;
240 while (mtx_spinlock_try(&syscons_mtx)) {
241 tsc_delay(1000); /* 1uS */
242 if (--retries == 0) {
243 mtx_init(&syscons_mtx, "syscons");
244 retries = 500000;
245 }
246 }
247 } else {
248 mtx_spinlock(&syscons_mtx);
249 }
82d1ed25
MD
250}
251
252/*
bd1cd9c2 253 * Returns 0 on success, EAGAIN on failure.
82d1ed25
MD
254 */
255static int
256syscons_lock_nonblock(void)
257{
bd1cd9c2 258 return(mtx_spinlock_try(&syscons_mtx));
82d1ed25
MD
259}
260
261static void
262syscons_unlock(void)
263{
bd1cd9c2 264 mtx_spinunlock(&syscons_mtx);
82d1ed25
MD
265}
266
267/*
268 * Console driver
269 */
984263bc
MD
270static cn_probe_t sccnprobe;
271static cn_init_t sccninit;
ce81f184 272static cn_init_t sccninit_fini;
984263bc
MD
273static cn_getc_t sccngetc;
274static cn_checkc_t sccncheckc;
275static cn_putc_t sccnputc;
276static cn_dbctl_t sccndbctl;
277static cn_term_t sccnterm;
ce7866b8 278static cn_poll_t sccnpoll;
984263bc 279
ce81f184 280CONS_DRIVER(sc, sccnprobe, sccninit, sccninit_fini, sccnterm,
ce7866b8 281 sccngetc, sccncheckc, sccnputc, sccndbctl, sccnpoll);
984263bc
MD
282
283static d_open_t scopen;
284static d_close_t scclose;
285static d_read_t scread;
286static d_ioctl_t scioctl;
287static d_mmap_t scmmap;
288
fef8985e 289static struct dev_ops sc_ops = {
481d12aa 290 { "sc", 0, D_TTY | D_MPSAFE },
fef8985e
MD
291 .d_open = scopen,
292 .d_close = scclose,
293 .d_read = scread,
294 .d_write = ttywrite,
295 .d_ioctl = scioctl,
fef8985e 296 .d_mmap = scmmap,
a32446b7
MD
297 .d_kqfilter = ttykqfilter,
298 .d_revoke = ttyrevoke
984263bc
MD
299};
300
301int
302sc_probe_unit(int unit, int flags)
303{
428805e9
IV
304 if ((flags & SC_EFI_FB) && (probe_efi_fb(0) != 0)) {
305 if (bootverbose)
306 kprintf("sc%d: no EFI framebuffer found.\n", unit);
307 flags &= ~SC_EFI_FB;
308 }
309
310 if (!(flags & SC_EFI_FB) && !scvidprobe(unit, flags, FALSE)) {
984263bc 311 if (bootverbose)
e3869ec7 312 kprintf("sc%d: no video adapter found.\n", unit);
984263bc
MD
313 return ENXIO;
314 }
315
316 /* syscons will be attached even when there is no keyboard */
317 sckbdprobe(unit, flags, FALSE);
318
319 return 0;
320}
321
717f4a47
SW
322int
323register_framebuffer(struct fb_info *info)
324{
61f2dcf2
IV
325 sc_softc_t *sc;
326
327 /* For now ignore framebuffers, which don't replace the vga display */
328 if (!info->is_vga_boot_display)
329 return 0;
330
2efb75f3 331 lwkt_gettoken(&vga_token);
61f2dcf2
IV
332 sc = sc_get_softc(0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
333 if (sc == NULL) {
2efb75f3 334 lwkt_reltoken(&vga_token);
61f2dcf2
IV
335 kprintf("%s: sc_get_softc(%d, %d) returned NULL\n", __func__,
336 0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
337 return 0;
338 }
717f4a47 339
61f2dcf2 340 /* Ignore this framebuffer if we already switched to KMS framebuffer */
ba409a88
IV
341 if (sc->fbi != NULL && sc->fbi != &efi_fb_info &&
342 sc->fbi != sc->dummy_fb_info) {
2efb75f3 343 lwkt_reltoken(&vga_token);
61f2dcf2
IV
344 return 0;
345 }
717f4a47 346
ba409a88
IV
347 if (sc->fb_set_par_task == NULL) {
348 sc->fb_set_par_task = kmalloc(sizeof(struct task),
349 M_SYSCONS, M_WAITOK | M_ZERO);
350 }
351 TASK_INIT(sc->fb_set_par_task, 0, sc_fb_set_par, sc);
f8b03d86
IV
352#if NSPLASH > 0
353 if (sc->fb_blank_task == NULL) {
354 sc->fb_blank_task = kmalloc(sizeof(struct task),
355 M_SYSCONS, M_WAITOK | M_ZERO);
356 }
357 TASK_INIT(sc->fb_blank_task, 0, sc_fb_blank, sc);
358#endif /* NSPLASH */
ba409a88
IV
359
360 /*
361 * Make sure that console messages don't interfere too much with
362 * modesetting.
363 */
364 atomic_add_int(&sc->videoio_in_progress, 1);
365
366 /* Lock against synchronous and asynchronous screen updates */
367 lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
368 syscons_lock();
61f2dcf2 369 sc->fbi = info;
ba409a88
IV
370 sc->fbi_generation++;
371 syscons_unlock();
717f4a47 372
2e53e344
IV
373 kprintf("kms console: xpixels %d ypixels %d\n",
374 sc->fbi->width, sc->fbi->height);
717f4a47 375 sc_update_render(sc->cur_scp);
ba409a88
IV
376 if (info->fbops.fb_set_par != NULL)
377 info->fbops.fb_set_par(info);
378 atomic_add_int(&sc->videoio_in_progress, -1);
717f4a47 379
43c88c9d
IV
380 sc->fb_blanked = FALSE;
381 if (sc->unit == sc_console_unit && sc->cur_scp->smode.mode != VT_AUTO)
382 cons_unavail = FALSE;
f8b03d86
IV
383#if NSPLASH > 0
384 if (info->fbops.fb_blank != NULL)
385 add_scrn_saver(scframebuffer_saver);
386#endif /* NSPLASH */
387
ba409a88 388 lockmgr(&sc_asynctd_lk, LK_RELEASE);
2efb75f3 389 lwkt_reltoken(&vga_token);
61f2dcf2 390 return 0;
717f4a47
SW
391}
392
ba409a88
IV
393void
394unregister_framebuffer(struct fb_info *info)
395{
396 sc_softc_t *sc;
397
2efb75f3 398 lwkt_gettoken(&vga_token);
ba409a88
IV
399 sc = sc_get_softc(0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
400 if (sc == NULL) {
2efb75f3 401 lwkt_reltoken(&vga_token);
ba409a88
IV
402 kprintf("%s: sc_get_softc(%d, %d) returned NULL\n", __func__,
403 0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
404 return;
405 }
406
407 if (sc->fbi != info) {
2efb75f3 408 lwkt_reltoken(&vga_token);
ba409a88
IV
409 return;
410 }
411
f8b03d86
IV
412#if NSPLASH > 0
413 if (info->fbops.fb_blank != NULL)
414 remove_scrn_saver(scframebuffer_saver);
415#endif /* NSPLASH */
416
ba409a88
IV
417 if (sc->fb_set_par_task != NULL &&
418 taskqueue_cancel(taskqueue_thread[0], sc->fb_set_par_task, NULL)) {
419 taskqueue_drain(taskqueue_thread[0], sc->fb_set_par_task);
420 }
f8b03d86
IV
421#if NSPLASH > 0
422 if (sc->fb_blank_task != NULL &&
423 taskqueue_cancel(taskqueue_thread[0], sc->fb_blank_task, NULL)) {
424 taskqueue_drain(taskqueue_thread[0], sc->fb_blank_task);
425 }
426#endif /* NSPLASH */
43c88c9d
IV
427 sc->fb_blanked = TRUE;
428 if (sc->unit == sc_console_unit)
429 cons_unavail = TRUE;
ba409a88
IV
430
431 if (sc->dummy_fb_info == NULL) {
432 sc->dummy_fb_info = kmalloc(sizeof(struct fb_info),
433 M_SYSCONS, M_WAITOK | M_ZERO);
434 } else {
435 memset(sc->dummy_fb_info, 0, sizeof(struct fb_info));
436 }
437 *sc->dummy_fb_info = *sc->fbi;
438 sc->dummy_fb_info->vaddr = 0;
439 sc->dummy_fb_info->fbops.fb_set_par = NULL;
440 sc->dummy_fb_info->fbops.fb_blank = NULL;
441 sc->dummy_fb_info->fbops.fb_debug_enter = NULL;
442
443 /* Lock against synchronous and asynchronous screen updates */
444 lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
445 syscons_lock();
446 sc->fbi = sc->dummy_fb_info;
447 syscons_unlock();
448 lockmgr(&sc_asynctd_lk, LK_RELEASE);
449
2efb75f3 450 lwkt_reltoken(&vga_token);
ba409a88
IV
451}
452
ff1a8594
IV
453void
454sc_font_scale(scr_stat *scp, int max_cols, int max_rows)
455{
456 int cols, rows;
457
458 /*
459 * If columns not specified in /boot/loader.conf then
460 * calculate a non-fractional scaling that yields a
461 * reasonable number of rows and columns. If it is <0,
462 * don't scale at all.
463 */
464 if (desired_cols == 0) {
465 int nomag = 1;
1ba5dede
IV
466 while (scp->xpixel / (scp->font_width * nomag) >= COL &&
467 scp->ypixel / (scp->font_height * nomag) >= ROW) {
ff1a8594
IV
468 ++nomag;
469 }
470 if (nomag > 1)
471 --nomag;
472 cols = scp->xpixel / (scp->font_width * nomag);
473 } else if (desired_cols < 0) {
474 cols = scp->xpixel / scp->font_width;
475 } else {
476 cols = desired_cols;
477 }
478 scp->blk_width = scp->xpixel / cols;
479 scp->blk_height = scp->blk_width * scp->font_height / scp->font_width;
480 rows = scp->ypixel / scp->blk_height;
481
482 /* scp->xsize = scp->xpixel / scp->blk_width; total possible */
483 scp->xsize = max_cols ? imin(max_cols, cols) : cols;
484 scp->ysize = max_rows ? imin(max_rows, rows) : rows;
485}
486
984263bc
MD
487/* probe video adapters, return TRUE if found */
488static int
489scvidprobe(int unit, int flags, int cons)
490{
491 /*
492 * Access the video adapter driver through the back door!
493 * Video adapter drivers need to be configured before syscons.
494 * However, when syscons is being probed as the low-level console,
495 * they have not been initialized yet. We force them to initialize
496 * themselves here. XXX
497 */
498 vid_configure(cons ? VIO_PROBE_ONLY : 0);
499
500 return (vid_find_adapter("*", unit) >= 0);
501}
502
503/* probe the keyboard, return TRUE if found */
504static int
505sckbdprobe(int unit, int flags, int cons)
506{
507 /* access the keyboard driver through the backdoor! */
508 kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
509
510 return (kbd_find_keyboard("*", unit) >= 0);
511}
512
dc98d15f
SW
513static char *
514adapter_name(video_adapter_t *adp)
984263bc
MD
515{
516 static struct {
517 int type;
518 char *name[2];
519 } names[] = {
520 { KD_MONO, { "MDA", "MDA" } },
521 { KD_HERCULES, { "Hercules", "Hercules" } },
522 { KD_CGA, { "CGA", "CGA" } },
523 { KD_EGA, { "EGA", "EGA (mono)" } },
524 { KD_VGA, { "VGA", "VGA (mono)" } },
984263bc
MD
525 { KD_TGA, { "TGA", "TGA" } },
526 { -1, { "Unknown", "Unknown" } },
527 };
528 int i;
529
530 for (i = 0; names[i].type != -1; ++i)
531 if (names[i].type == adp->va_type)
532 break;
533 return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
534}
535
536int
537sc_attach_unit(int unit, int flags)
538{
539 sc_softc_t *sc;
540 scr_stat *scp;
984263bc 541 int vc;
b13267a5 542 cdev_t dev;
984263bc 543 flags &= ~SC_KERNEL_CONSOLE;
49ecae83 544 char tbuf[MAKEDEV_MINNBUF];
984263bc 545
428805e9
IV
546 if ((flags & SC_EFI_FB) && probe_efi_fb(0) != 0)
547 flags &= ~SC_EFI_FB;
548
984263bc
MD
549 if (sc_console_unit == unit) {
550 /*
551 * If this unit is being used as the system console, we need to
552 * adjust some variables and buffers before and after scinit().
553 */
554 /* assert(sc_console != NULL) */
555 flags |= SC_KERNEL_CONSOLE;
556 scmeminit(NULL);
557
558 scinit(unit, flags);
559
560 if (sc_console->tsw->te_size > 0) {
561 /* assert(sc_console->ts != NULL); */
562 kernel_console_ts = sc_console->ts;
77652cad 563 sc_console->ts = kmalloc(sc_console->tsw->te_size,
b721b9ee 564 M_SYSCONS, M_WAITOK);
984263bc
MD
565 bcopy(kernel_console_ts, sc_console->ts, sc_console->tsw->te_size);
566 (*sc_console->tsw->te_default_attr)(sc_console,
567 user_default.std_color,
568 user_default.rev_color);
569 }
570 } else {
571 scinit(unit, flags);
572 }
573
574 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
ce81f184
MD
575
576 /*
577 * If this is the console we couldn't setup sc->dev before because
578 * malloc wasn't working. Set it up now.
579 */
580 if (flags & SC_KERNEL_CONSOLE) {
581 KKASSERT(sc->dev == NULL);
582 sc->dev = kmalloc(sizeof(cdev_t)*sc->vtys, M_SYSCONS, M_WAITOK|M_ZERO);
49ecae83 583 sc->dev[0] = make_dev(&sc_ops, sc_console_unit*MAXCONS, UID_ROOT,
584 GID_WHEEL, 0600, "ttyv%s", makedev_unit_b32(tbuf,
585 sc_console_unit * MAXCONS));
2efb75f3 586 ttymalloc(&sc->dev[0]->si_tty);
ce81f184
MD
587 sc->dev[0]->si_drv1 = sc_console;
588 }
589
590 /*
591 * Finish up the standard attach
592 */
984263bc 593 sc->config = flags;
bf0ecf68 594 callout_init_mp(&sc->scrn_timer_ch);
984263bc
MD
595 scp = SC_STAT(sc->dev[0]);
596 if (sc_console == NULL) /* sc_console_unit < 0 */
597 sc_console = scp;
598
984263bc
MD
599 /* initialize cursor */
600 if (!ISGRAPHSC(scp))
601 update_cursor_image(scp);
602
603 /* get screen update going */
604 scrn_timer(sc);
605
606 /* set up the keyboard */
607 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
f6ce8b19 608 update_kbd_state(scp, scp->status, LOCK_MASK, FALSE);
984263bc 609
e3869ec7 610 kprintf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
428805e9
IV
611 unit, (sc->config & SC_EFI_FB) ? "EFI_FB" : adapter_name(sc->adp),
612 sc->vtys, sc->config);
984263bc 613 if (bootverbose) {
e3869ec7 614 kprintf("sc%d:", unit);
984263bc 615 if (sc->adapter >= 0)
e3869ec7 616 kprintf(" fb%d", sc->adapter);
984263bc 617 if (sc->keyboard >= 0)
e3869ec7 618 kprintf(", kbd%d", sc->keyboard);
984263bc 619 if (scp->tsw)
e3869ec7 620 kprintf(", terminal emulator: %s (%s)",
984263bc 621 scp->tsw->te_name, scp->tsw->te_desc);
e3869ec7 622 kprintf("\n");
984263bc
MD
623 }
624
625 /* register a shutdown callback for the kernel console */
626 if (sc_console_unit == unit)
627 EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown,
628 (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
629
e4c9c0c8 630 /*
3e82b46c
MD
631 * create devices.
632 *
633 * The first vty already has struct tty and scr_stat initialized
634 * in scinit(). The other vtys will have these structs when
635 * first opened.
e4c9c0c8 636 */
3e82b46c 637 for (vc = 1; vc < sc->vtys; vc++) {
fef8985e 638 dev = make_dev(&sc_ops, vc + unit * MAXCONS,
49ecae83 639 UID_ROOT, GID_WHEEL, 0600, "ttyv%s",
640 makedev_unit_b32(tbuf, vc + unit * MAXCONS));
984263bc 641 sc->dev[vc] = dev;
984263bc 642 }
cd29885a
MD
643 cctl_dev = make_dev(&sc_ops, SC_CONSOLECTL,
644 UID_ROOT, GID_WHEEL, 0600, "consolectl");
2efb75f3 645 cctl_dev->si_tty = ttymalloc(&sc_console_tty);
cd29885a 646 cctl_dev->si_drv1 = sc_console;
984263bc
MD
647 return 0;
648}
649
650static void
651scmeminit(void *arg)
652{
653 if (sc_malloc)
654 return;
655 sc_malloc = TRUE;
656
657 /*
658 * As soon as malloc() becomes functional, we had better allocate
659 * various buffers for the kernel console.
660 */
661
662 if (sc_console_unit < 0) /* sc_console == NULL */
663 return;
664
665 /* copy the temporary buffer to the final buffer */
53f1c39c 666 sc_alloc_scr_buffer(sc_console, TRUE, FALSE);
984263bc
MD
667
668#ifndef SC_NO_CUTPASTE
53f1c39c 669 sc_alloc_cut_buffer(sc_console, TRUE);
984263bc
MD
670#endif
671
672#ifndef SC_NO_HISTORY
673 /* initialize history buffer & pointers */
53f1c39c 674 sc_alloc_history_buffer(sc_console, 0, 0, TRUE);
984263bc 675#endif
88af68e6
IV
676
677 /* Fill initial terminal border, efi_fb_info.vaddr should be non-NULL now */
678 if (!sc_filled_border) {
679 sc_filled_border = TRUE;
680 sc_set_border(sc_console, sc_console->border);
681 }
984263bc
MD
682}
683
ba39e2e0 684SYSINIT(sc_mem, SI_BOOT1_POST, SI_ORDER_ANY, scmeminit, NULL);
984263bc
MD
685
686static int
b13267a5 687scdevtounit(cdev_t dev)
984263bc
MD
688{
689 int vty = SC_VTY(dev);
690
691 if (vty == SC_CONSOLECTL)
692 return ((sc_console != NULL) ? sc_console->sc->unit : -1);
693 else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
694 return -1;
695 else
696 return vty/MAXCONS;
697}
698
bc3912c4 699static int
fef8985e 700scopen(struct dev_open_args *ap)
984263bc 701{
b13267a5 702 cdev_t dev = ap->a_head.a_dev;
22ff886e 703 int unit;
984263bc
MD
704 sc_softc_t *sc;
705 struct tty *tp;
706 scr_stat *scp;
707 keyarg_t key;
708 int error;
709
2efb75f3 710 lwkt_gettoken(&vga_token);
22ff886e 711 unit = scdevtounit(dev);
984263bc
MD
712 DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
713 major(dev), minor(dev), unit, SC_VTY(dev)));
714
715 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
22ff886e 716 if (sc == NULL) {
2efb75f3 717 lwkt_reltoken(&vga_token);
984263bc 718 return ENXIO;
22ff886e 719 }
984263bc 720
2efb75f3
MD
721 tp = ttymalloc(&dev->si_tty);
722 lwkt_gettoken(&tp->t_token);
984263bc
MD
723 tp->t_oproc = scstart;
724 tp->t_param = scparam;
725 tp->t_stop = nottystop;
cd29885a 726
984263bc 727 tp->t_dev = dev;
cd29885a 728
984263bc
MD
729 if (!ISTTYOPEN(tp)) {
730 ttychars(tp);
731 /* Use the current setting of the <-- key as default VERASE. */
732 /* If the Delete key is preferable, an stty is necessary */
733 if (sc->kbd != NULL) {
734 key.keynum = KEYCODE_BS;
735 kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
736 tp->t_cc[VERASE] = key.key.map[0];
737 }
738 tp->t_iflag = TTYDEF_IFLAG;
739 tp->t_oflag = TTYDEF_OFLAG;
740 tp->t_cflag = TTYDEF_CFLAG;
741 tp->t_lflag = TTYDEF_LFLAG;
742 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
743 scparam(tp, &tp->t_termios);
744 (*linesw[tp->t_line].l_modem)(tp, 1);
745 }
746 else
22ff886e 747 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
2efb75f3
MD
748 lwkt_reltoken(&tp->t_token);
749 lwkt_reltoken(&vga_token);
984263bc 750 return(EBUSY);
22ff886e 751 }
984263bc
MD
752
753 error = (*linesw[tp->t_line].l_open)(dev, tp);
754
755 scp = SC_STAT(dev);
756 if (scp == NULL) {
848cc936 757 scp = dev->si_drv1 = alloc_scp(sc, SC_VTY(dev));
bd1cd9c2 758 syscons_lock();
984263bc
MD
759 if (ISGRAPHSC(scp))
760 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
bd1cd9c2 761 syscons_unlock();
984263bc
MD
762 }
763 if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
764 tp->t_winsize.ws_col = scp->xsize;
765 tp->t_winsize.ws_row = scp->ysize;
766 }
767
7ae6dbf0
MD
768 /*
769 * Start optional support thread for syscons refreshes. This thread
770 * will execute the refresh without the syscons_lock held and will
771 * allow interrupts while it is doing so.
772 */
773 if (scp->asynctd == NULL) {
774 lwkt_create(scrn_update_thread, scp, &scp->asynctd, NULL, 0, -1,
775 "syscons%d", SC_VTY(dev));
776 }
2efb75f3
MD
777 lwkt_reltoken(&tp->t_token);
778 lwkt_reltoken(&vga_token);
779
984263bc
MD
780 return error;
781}
782
bc3912c4 783static int
fef8985e 784scclose(struct dev_close_args *ap)
984263bc 785{
b13267a5 786 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
787 struct tty *tp = dev->si_tty;
788 scr_stat *scp;
984263bc 789
2efb75f3
MD
790 lwkt_gettoken(&vga_token);
791 lwkt_gettoken(&tp->t_token);
984263bc
MD
792 if (SC_VTY(dev) != SC_CONSOLECTL) {
793 scp = SC_STAT(tp->t_dev);
794 /* were we in the middle of the VT switching process? */
795 DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
43c88c9d
IV
796 if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit) &&
797 !scp->sc->fb_blanked) {
984263bc 798 cons_unavail = FALSE;
43c88c9d 799 }
6bc31f17 800 if (finish_vt_rel(scp, TRUE) == 0) /* force release */
984263bc
MD
801 DPRINTF(5, ("reset WAIT_REL, "));
802 if (finish_vt_acq(scp) == 0) /* force acknowledge */
803 DPRINTF(5, ("reset WAIT_ACQ, "));
bd1cd9c2 804 syscons_lock();
122df98f 805#if 0 /* notyet */
984263bc
MD
806 if (scp == &main_console) {
807 scp->pid = 0;
808 scp->proc = NULL;
809 scp->smode.mode = VT_AUTO;
810 }
811 else {
812 sc_vtb_destroy(&scp->vtb);
813 sc_vtb_destroy(&scp->scr);
814 sc_free_history_buffer(scp, scp->ysize);
815 SC_STAT(dev) = NULL;
efda3bd0 816 kfree(scp, M_SYSCONS);
984263bc
MD
817 }
818#else
819 scp->pid = 0;
820 scp->proc = NULL;
821 scp->smode.mode = VT_AUTO;
822#endif
823 scp->kbd_mode = K_XLATE;
bd1cd9c2 824 syscons_unlock();
984263bc
MD
825 if (scp == scp->sc->cur_scp)
826 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
827 DPRINTF(5, ("done.\n"));
828 }
fef8985e 829 (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
984263bc 830 ttyclose(tp);
2efb75f3
MD
831 lwkt_reltoken(&tp->t_token);
832 lwkt_reltoken(&vga_token);
cd29885a 833
984263bc
MD
834 return(0);
835}
836
bc3912c4 837static int
fef8985e 838scread(struct dev_read_args *ap)
984263bc 839{
22ff886e
AH
840 int ret;
841
2efb75f3 842 lwkt_gettoken(&vga_token);
984263bc 843 sc_touch_scrn_saver();
bd1cd9c2 844 ret = ttyread(ap);
2efb75f3 845 lwkt_reltoken(&vga_token);
22ff886e 846 return ret;
984263bc
MD
847}
848
849static int
850sckbdevent(keyboard_t *thiskbd, int event, void *arg)
851{
852 sc_softc_t *sc;
853 struct tty *cur_tty;
854 int c;
855 size_t len;
856 u_char *cp;
857
2efb75f3 858 lwkt_gettoken(&vga_token);
59306b36
MD
859 /*
860 * WARNING: In early boot sc->dev may not be setup yet.
861 */
984263bc
MD
862 sc = (sc_softc_t *)arg;
863 /* assert(thiskbd == sc->kbd) */
864
865 switch (event) {
866 case KBDIO_KEYINPUT:
ce7866b8 867 if (sc->kbd && sc->kbd->kb_flags & KB_POLLED) {
2efb75f3 868 lwkt_reltoken(&vga_token);
ce7866b8
MD
869 return 0;
870 }
984263bc
MD
871 break;
872 case KBDIO_UNLOADING:
bd1cd9c2 873 syscons_lock();
984263bc
MD
874 sc->kbd = NULL;
875 sc->keyboard = -1;
bd1cd9c2 876 syscons_unlock();
984263bc 877 kbd_release(thiskbd, (void *)&sc->keyboard);
2efb75f3 878 lwkt_reltoken(&vga_token);
984263bc
MD
879 return 0;
880 default:
2efb75f3 881 lwkt_reltoken(&vga_token);
984263bc
MD
882 return EINVAL;
883 }
884
885 /*
886 * Loop while there is still input to get from the keyboard.
887 * I don't think this is nessesary, and it doesn't fix
888 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
889 */
890 while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
984263bc
MD
891 cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
892 if (!ISTTYOPEN(cur_tty)) {
893 cur_tty = sc_console_tty;
894 if (!ISTTYOPEN(cur_tty))
895 continue;
896 }
897
bd1cd9c2
MD
898 syscons_lock();
899 if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty)) {
900 syscons_unlock();
984263bc 901 continue;
bd1cd9c2
MD
902 }
903 syscons_unlock();
984263bc 904
2efb75f3
MD
905 lwkt_gettoken(&cur_tty->t_token);
906
984263bc
MD
907 switch (KEYFLAGS(c)) {
908 case 0x0000: /* normal key */
909 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
910 break;
911 case FKEY: /* function key, return string */
912 cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
913 if (cp != NULL) {
914 while (len-- > 0)
915 (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
916 }
917 break;
918 case MKEY: /* meta is active, prepend ESC */
919 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
920 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
921 break;
922 case BKEY: /* backtab fixed sequence (esc [ Z) */
923 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
924 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
925 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
926 break;
927 }
2efb75f3 928 lwkt_reltoken(&cur_tty->t_token);
984263bc
MD
929 }
930
bd1cd9c2 931 syscons_lock();
984263bc 932 sc->cur_scp->status |= MOUSE_HIDDEN;
bd1cd9c2 933 syscons_unlock();
984263bc 934
2efb75f3 935 lwkt_reltoken(&vga_token);
984263bc
MD
936 return 0;
937}
938
939static int
940scparam(struct tty *tp, struct termios *t)
941{
2efb75f3 942 lwkt_gettoken(&tp->t_token);
984263bc
MD
943 tp->t_ispeed = t->c_ispeed;
944 tp->t_ospeed = t->c_ospeed;
945 tp->t_cflag = t->c_cflag;
2efb75f3
MD
946 lwkt_reltoken(&tp->t_token);
947
984263bc
MD
948 return 0;
949}
950
bc3912c4 951static int
fef8985e 952scioctl(struct dev_ioctl_args *ap)
984263bc 953{
b13267a5 954 cdev_t dev = ap->a_head.a_dev;
fef8985e
MD
955 u_long cmd = ap->a_cmd;
956 caddr_t data = ap->a_data;
957 int flag = ap->a_fflag;
984263bc
MD
958 int error;
959 int i;
960 struct tty *tp;
961 sc_softc_t *sc;
962 scr_stat *scp;
dadab5e9 963
2efb75f3 964 lwkt_gettoken(&vga_token);
984263bc
MD
965 tp = dev->si_tty;
966
fef8985e 967 error = sc_vid_ioctl(tp, cmd, data, flag);
22ff886e 968 if (error != ENOIOCTL) {
2efb75f3 969 lwkt_reltoken(&vga_token);
984263bc 970 return error;
22ff886e 971 }
984263bc
MD
972
973#ifndef SC_NO_HISTORY
fef8985e 974 error = sc_hist_ioctl(tp, cmd, data, flag);
22ff886e 975 if (error != ENOIOCTL) {
2efb75f3 976 lwkt_reltoken(&vga_token);
984263bc 977 return error;
22ff886e 978 }
984263bc
MD
979#endif
980
981#ifndef SC_NO_SYSMOUSE
fef8985e 982 error = sc_mouse_ioctl(tp, cmd, data, flag);
22ff886e 983 if (error != ENOIOCTL) {
2efb75f3 984 lwkt_reltoken(&vga_token);
984263bc 985 return error;
22ff886e 986 }
984263bc
MD
987#endif
988
989 scp = SC_STAT(tp->t_dev);
990 /* assert(scp != NULL) */
991 /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
992 sc = scp->sc;
993
994 if (scp->tsw) {
bd1cd9c2 995 syscons_lock();
fef8985e 996 error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, flag);
bd1cd9c2 997 syscons_unlock();
22ff886e 998 if (error != ENOIOCTL) {
2efb75f3 999 lwkt_reltoken(&vga_token);
984263bc 1000 return error;
22ff886e 1001 }
984263bc
MD
1002 }
1003
1004 switch (cmd) { /* process console hardware related ioctl's */
1005
1006 case GIO_ATTR: /* get current attributes */
1007 /* this ioctl is not processed here, but in the terminal emulator */
2efb75f3 1008 lwkt_reltoken(&vga_token);
984263bc
MD
1009 return ENOTTY;
1010
1011 case GIO_COLOR: /* is this a color console ? */
2b5f463d
IV
1012 if (sc->fbi != NULL)
1013 *(int *)data = 1;
1014 else
1015 *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
2efb75f3 1016 lwkt_reltoken(&vga_token);
984263bc
MD
1017 return 0;
1018
1019 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
22ff886e 1020 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME) {
2efb75f3 1021 lwkt_reltoken(&vga_token);
984263bc 1022 return EINVAL;
22ff886e 1023 }
bd1cd9c2 1024 syscons_lock();
984263bc
MD
1025 scrn_blank_time = *(int *)data;
1026 run_scrn_saver = (scrn_blank_time != 0);
bd1cd9c2 1027 syscons_unlock();
2efb75f3 1028 lwkt_reltoken(&vga_token);
984263bc
MD
1029 return 0;
1030
1031 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
bd1cd9c2 1032 syscons_lock();
984263bc
MD
1033 if (!ISGRAPHSC(sc->cur_scp))
1034 sc_remove_cursor_image(sc->cur_scp);
1035 if ((*(int*)data) & 0x01)
1036 sc->flags |= SC_BLINK_CURSOR;
1037 else
1038 sc->flags &= ~SC_BLINK_CURSOR;
1039 if ((*(int*)data) & 0x02) {
1040 sc->flags |= SC_CHAR_CURSOR;
1041 } else
1042 sc->flags &= ~SC_CHAR_CURSOR;
1043 /*
1044 * The cursor shape is global property; all virtual consoles
1045 * are affected. Update the cursor in the current console...
1046 */
1047 if (!ISGRAPHSC(sc->cur_scp)) {
1048 sc_set_cursor_image(sc->cur_scp);
1049 sc_draw_cursor_image(sc->cur_scp);
1050 }
bd1cd9c2 1051 syscons_unlock();
2efb75f3 1052 lwkt_reltoken(&vga_token);
984263bc
MD
1053 return 0;
1054
1055 case CONS_BELLTYPE: /* set bell type sound/visual */
bd1cd9c2
MD
1056 syscons_lock();
1057
984263bc
MD
1058 if ((*(int *)data) & 0x01)
1059 sc->flags |= SC_VISUAL_BELL;
1060 else
1061 sc->flags &= ~SC_VISUAL_BELL;
bd1cd9c2 1062
984263bc
MD
1063 if ((*(int *)data) & 0x02)
1064 sc->flags |= SC_QUIET_BELL;
1065 else
1066 sc->flags &= ~SC_QUIET_BELL;
bd1cd9c2
MD
1067
1068 syscons_unlock();
2efb75f3 1069 lwkt_reltoken(&vga_token);
984263bc
MD
1070 return 0;
1071
1072 case CONS_GETINFO: /* get current (virtual) console info */
1073 {
1074 vid_info_t *ptr = (vid_info_t*)data;
1075 if (ptr->size == sizeof(struct vid_info)) {
1076 ptr->m_num = sc->cur_scp->index;
219917ca 1077 ptr->font_size = scp->font_height;
984263bc
MD
1078 ptr->mv_col = scp->xpos;
1079 ptr->mv_row = scp->ypos;
1080 ptr->mv_csz = scp->xsize;
1081 ptr->mv_rsz = scp->ysize;
1082 /*
1083 * The following fields are filled by the terminal emulator. XXX
1084 *
1085 * ptr->mv_norm.fore
1086 * ptr->mv_norm.back
1087 * ptr->mv_rev.fore
1088 * ptr->mv_rev.back
1089 */
1090 ptr->mv_grfc.fore = 0; /* not supported */
1091 ptr->mv_grfc.back = 0; /* not supported */
1092 ptr->mv_ovscan = scp->border;
1093 if (scp == sc->cur_scp)
f6ce8b19 1094 save_kbd_state(scp, FALSE);
984263bc 1095 ptr->mk_keylock = scp->status & LOCK_MASK;
2efb75f3 1096 lwkt_reltoken(&vga_token);
984263bc
MD
1097 return 0;
1098 }
2efb75f3 1099 lwkt_reltoken(&vga_token);
984263bc
MD
1100 return EINVAL;
1101 }
1102
1103 case CONS_GETVERS: /* get version number */
1104 *(int*)data = 0x200; /* version 2.0 */
2efb75f3 1105 lwkt_reltoken(&vga_token);
984263bc
MD
1106 return 0;
1107
1108 case CONS_IDLE: /* see if the screen has been idle */
1109 /*
1110 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
1111 * the user process may have been writing something on the
1112 * screen and syscons is not aware of it. Declare the screen
1113 * is NOT idle if it is in one of these modes. But there is
1114 * an exception to it; if a screen saver is running in the
1115 * graphics mode in the current screen, we should say that the
1116 * screen has been idle.
1117 */
1118 *(int *)data = (sc->flags & SC_SCRN_IDLE)
1119 && (!ISGRAPHSC(sc->cur_scp)
1120 || (sc->cur_scp->status & SAVER_RUNNING));
2efb75f3 1121 lwkt_reltoken(&vga_token);
984263bc
MD
1122 return 0;
1123
1124 case CONS_SAVERMODE: /* set saver mode */
1125 switch(*(int *)data) {
1126 case CONS_NO_SAVER:
1127 case CONS_USR_SAVER:
bd1cd9c2 1128 syscons_lock();
984263bc
MD
1129 /* if a LKM screen saver is running, stop it first. */
1130 scsplash_stick(FALSE);
1131 saver_mode = *(int *)data;
984263bc 1132#if NSPLASH > 0
0510b0ee 1133 if ((error = wait_scrn_saver_stop(NULL, TRUE))) {
bd1cd9c2 1134 syscons_unlock();
2efb75f3 1135 lwkt_reltoken(&vga_token);
984263bc
MD
1136 return error;
1137 }
1138#endif /* NSPLASH */
1139 run_scrn_saver = TRUE;
1140 if (saver_mode == CONS_USR_SAVER)
1141 scp->status |= SAVER_RUNNING;
1142 else
1143 scp->status &= ~SAVER_RUNNING;
1144 scsplash_stick(TRUE);
bd1cd9c2 1145 syscons_unlock();
984263bc
MD
1146 break;
1147 case CONS_LKM_SAVER:
bd1cd9c2 1148 syscons_lock();
984263bc
MD
1149 if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
1150 scp->status &= ~SAVER_RUNNING;
1151 saver_mode = *(int *)data;
bd1cd9c2 1152 syscons_unlock();
984263bc
MD
1153 break;
1154 default:
2efb75f3 1155 lwkt_reltoken(&vga_token);
984263bc
MD
1156 return EINVAL;
1157 }
2efb75f3 1158 lwkt_reltoken(&vga_token);
984263bc
MD
1159 return 0;
1160
1161 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
1162 /*
1163 * Note that this ioctl does not guarantee the screen saver
1164 * actually starts or stops. It merely attempts to do so...
1165 */
bd1cd9c2 1166 syscons_lock();
984263bc
MD
1167 run_scrn_saver = (*(int *)data != 0);
1168 if (run_scrn_saver)
1169 sc->scrn_time_stamp -= scrn_blank_time;
bd1cd9c2 1170 syscons_unlock();
2efb75f3 1171 lwkt_reltoken(&vga_token);
984263bc
MD
1172 return 0;
1173
1174 case CONS_SCRSHOT: /* get a screen shot */
1175 {
1176 scrshot_t *ptr = (scrshot_t*)data;
bd1cd9c2 1177 syscons_lock();
984263bc 1178 if (ISGRAPHSC(scp)) {
bd1cd9c2 1179 syscons_unlock();
2efb75f3 1180 lwkt_reltoken(&vga_token);
984263bc
MD
1181 return EOPNOTSUPP;
1182 }
1183 if (scp->xsize != ptr->xsize || scp->ysize != ptr->ysize) {
bd1cd9c2 1184 syscons_unlock();
2efb75f3 1185 lwkt_reltoken(&vga_token);
984263bc
MD
1186 return EINVAL;
1187 }
bd1cd9c2 1188 syscons_unlock();
984263bc 1189 copyout ((void*)scp->vtb.vtb_buffer, ptr->buf,
47d95543 1190 ptr->xsize * ptr->ysize * sizeof(uint16_t));
2efb75f3 1191 lwkt_reltoken(&vga_token);
984263bc
MD
1192 return 0;
1193 }
1194
1195 case VT_SETMODE: /* set screen switcher mode */
1196 {
1197 struct vt_mode *mode;
1198
1199 mode = (struct vt_mode *)data;
1200 DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
1201 if (scp->smode.mode == VT_PROCESS) {
58c2553a 1202 if (scp->proc == pfindn(scp->pid) && scp->proc != curproc) {
984263bc 1203 DPRINTF(5, ("error EPERM\n"));
2efb75f3 1204 lwkt_reltoken(&vga_token);
984263bc
MD
1205 return EPERM;
1206 }
1207 }
bd1cd9c2 1208 syscons_lock();
984263bc
MD
1209 if (mode->mode == VT_AUTO) {
1210 scp->smode.mode = VT_AUTO;
1211 scp->proc = NULL;
1212 scp->pid = 0;
1213 DPRINTF(5, ("VT_AUTO, "));
43c88c9d
IV
1214 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit) &&
1215 !sc->fb_blanked) {
984263bc 1216 cons_unavail = FALSE;
43c88c9d 1217 }
6bc31f17 1218 if (finish_vt_rel(scp, TRUE) == 0)
984263bc
MD
1219 DPRINTF(5, ("reset WAIT_REL, "));
1220 if (finish_vt_acq(scp) == 0)
1221 DPRINTF(5, ("reset WAIT_ACQ, "));
1222 } else {
1223 if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
1224 || !ISSIGVALID(mode->frsig)) {
bd1cd9c2 1225 syscons_unlock();
984263bc 1226 DPRINTF(5, ("error EINVAL\n"));
2efb75f3 1227 lwkt_reltoken(&vga_token);
984263bc
MD
1228 return EINVAL;
1229 }
fef8985e 1230 DPRINTF(5, ("VT_PROCESS %d, ", curproc->p_pid));
984263bc 1231 bcopy(data, &scp->smode, sizeof(struct vt_mode));
fef8985e 1232 scp->proc = curproc;
984263bc
MD
1233 scp->pid = scp->proc->p_pid;
1234 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
1235 cons_unavail = TRUE;
1236 }
bd1cd9c2 1237 syscons_unlock();
984263bc 1238 DPRINTF(5, ("\n"));
2efb75f3 1239 lwkt_reltoken(&vga_token);
984263bc
MD
1240 return 0;
1241 }
1242
1243 case VT_GETMODE: /* get screen switcher mode */
1244 bcopy(&scp->smode, data, sizeof(struct vt_mode));
2efb75f3 1245 lwkt_reltoken(&vga_token);
984263bc
MD
1246 return 0;
1247
1248 case VT_RELDISP: /* screen switcher ioctl */
984263bc
MD
1249 /*
1250 * This must be the current vty which is in the VT_PROCESS
1251 * switching mode...
1252 */
bd1cd9c2 1253 syscons_lock();
984263bc 1254 if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
bd1cd9c2 1255 syscons_unlock();
2efb75f3 1256 lwkt_reltoken(&vga_token);
984263bc
MD
1257 return EINVAL;
1258 }
1259 /* ...and this process is controlling it. */
fef8985e 1260 if (scp->proc != curproc) {
bd1cd9c2 1261 syscons_unlock();
2efb75f3 1262 lwkt_reltoken(&vga_token);
984263bc
MD
1263 return EPERM;
1264 }
1265 error = EINVAL;
1266 switch(*(int *)data) {
1267 case VT_FALSE: /* user refuses to release screen, abort */
6bc31f17 1268 if ((error = finish_vt_rel(scp, FALSE)) == 0)
984263bc
MD
1269 DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
1270 break;
1271 case VT_TRUE: /* user has released screen, go on */
6bc31f17 1272 if ((error = finish_vt_rel(scp, TRUE)) == 0)
984263bc
MD
1273 DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
1274 break;
1275 case VT_ACKACQ: /* acquire acknowledged, switch completed */
1276 if ((error = finish_vt_acq(scp)) == 0)
1277 DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
0d7c8a4d
IV
1278 syscons_unlock();
1279 /* Wait for drm modesetting callback to finish. */
2efb75f3 1280 lwkt_reltoken(&vga_token);
e3657467
IV
1281 if (sc->fb_set_par_task != NULL)
1282 taskqueue_drain(taskqueue_thread[0], sc->fb_set_par_task);
0d7c8a4d 1283 return error;
984263bc
MD
1284 default:
1285 break;
1286 }
bd1cd9c2 1287 syscons_unlock();
2efb75f3 1288 lwkt_reltoken(&vga_token);
984263bc
MD
1289 return error;
1290
1291 case VT_OPENQRY: /* return free virtual console */
1292 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
1293 tp = VIRTUAL_TTY(sc, i);
1294 if (!ISTTYOPEN(tp)) {
1295 *(int *)data = i + 1;
2efb75f3 1296 lwkt_reltoken(&vga_token);
984263bc
MD
1297 return 0;
1298 }
1299 }
2efb75f3 1300 lwkt_reltoken(&vga_token);
984263bc
MD
1301 return EINVAL;
1302
1303 case VT_ACTIVATE: /* switch to screen *data */
1304 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
bd1cd9c2 1305 syscons_lock();
0510b0ee 1306 sc_clean_up(sc->cur_scp, TRUE);
bd1cd9c2
MD
1307 error = sc_switch_scr(sc, i);
1308 syscons_unlock();
2efb75f3 1309 lwkt_reltoken(&vga_token);
bd1cd9c2 1310 return error;
984263bc
MD
1311
1312 case VT_WAITACTIVE: /* wait for switch to occur */
1313 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
22ff886e 1314 if ((i < sc->first_vty) || (i >= sc->first_vty + sc->vtys)) {
2efb75f3 1315 lwkt_reltoken(&vga_token);
984263bc 1316 return EINVAL;
22ff886e 1317 }
bd1cd9c2 1318 syscons_lock();
0510b0ee 1319 error = sc_clean_up(sc->cur_scp, TRUE);
bd1cd9c2 1320 syscons_unlock();
22ff886e 1321 if (error) {
2efb75f3 1322 lwkt_reltoken(&vga_token);
984263bc 1323 return error;
22ff886e 1324 }
8aefdd25
MD
1325
1326 /*
1327 * scp might be NULL, we aren't sure why. Check for NULL.
1328 *
1329 * http://bugs.dragonflybsd.org/issues/2481
1330 */
984263bc 1331 scp = SC_STAT(SC_DEV(sc, i));
8aefdd25 1332 if (scp == NULL || scp == scp->sc->cur_scp) {
2efb75f3 1333 lwkt_reltoken(&vga_token);
984263bc 1334 return 0;
22ff886e 1335 }
f3628b86
MD
1336 error = tsleep((caddr_t)&scp->smode, PCATCH, "waitvt", 0);
1337 /* May return ERESTART */
2efb75f3 1338 lwkt_reltoken(&vga_token);
0d7c8a4d 1339 /* Wait for drm modesetting callback to finish. */
e3657467
IV
1340 if (sc->fb_set_par_task != NULL)
1341 taskqueue_drain(taskqueue_thread[0], sc->fb_set_par_task);
984263bc
MD
1342 return error;
1343
1344 case VT_GETACTIVE: /* get active vty # */
1345 *(int *)data = sc->cur_scp->index + 1;
2efb75f3 1346 lwkt_reltoken(&vga_token);
984263bc
MD
1347 return 0;
1348
1349 case VT_GETINDEX: /* get this vty # */
1350 *(int *)data = scp->index + 1;
2efb75f3 1351 lwkt_reltoken(&vga_token);
984263bc
MD
1352 return 0;
1353
1354 case VT_LOCKSWITCH: /* prevent vty switching */
bd1cd9c2 1355 syscons_lock();
984263bc
MD
1356 if ((*(int *)data) & 0x01)
1357 sc->flags |= SC_SCRN_VTYLOCK;
1358 else
1359 sc->flags &= ~SC_SCRN_VTYLOCK;
bd1cd9c2 1360 syscons_unlock();
2efb75f3 1361 lwkt_reltoken(&vga_token);
984263bc
MD
1362 return 0;
1363
1364 case KDENABIO: /* allow io operations */
895c1f85 1365 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
22ff886e 1366 if (error != 0) {
2efb75f3 1367 lwkt_reltoken(&vga_token);
984263bc 1368 return error;
22ff886e
AH
1369 }
1370 if (securelevel > 0) {
2efb75f3 1371 lwkt_reltoken(&vga_token);
984263bc 1372 return EPERM;
22ff886e 1373 }
483114b6 1374#if defined(__x86_64__)
0855a2af
JG
1375 curthread->td_lwp->lwp_md.md_regs->tf_rflags |= PSL_IOPL;
1376#endif
2efb75f3 1377 lwkt_reltoken(&vga_token);
984263bc
MD
1378 return 0;
1379
1380 case KDDISABIO: /* disallow io operations (default) */
483114b6 1381#if defined(__x86_64__)
0855a2af
JG
1382 curthread->td_lwp->lwp_md.md_regs->tf_rflags &= ~PSL_IOPL;
1383#endif
2efb75f3 1384 lwkt_reltoken(&vga_token);
984263bc
MD
1385 return 0;
1386
1387 case KDSKBSTATE: /* set keyboard state (locks) */
22ff886e 1388 if (*(int *)data & ~LOCK_MASK) {
2efb75f3 1389 lwkt_reltoken(&vga_token);
984263bc 1390 return EINVAL;
22ff886e 1391 }
bd1cd9c2 1392 syscons_lock();
984263bc
MD
1393 scp->status &= ~LOCK_MASK;
1394 scp->status |= *(int *)data;
bd1cd9c2 1395 syscons_unlock();
984263bc 1396 if (scp == sc->cur_scp)
f6ce8b19 1397 update_kbd_state(scp, scp->status, LOCK_MASK, FALSE);
2efb75f3 1398 lwkt_reltoken(&vga_token);
984263bc
MD
1399 return 0;
1400
1401 case KDGKBSTATE: /* get keyboard state (locks) */
1402 if (scp == sc->cur_scp)
f6ce8b19 1403 save_kbd_state(scp, FALSE);
984263bc 1404 *(int *)data = scp->status & LOCK_MASK;
2efb75f3 1405 lwkt_reltoken(&vga_token);
984263bc
MD
1406 return 0;
1407
1408 case KDGETREPEAT: /* get keyboard repeat & delay rates */
1409 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */
1410 error = kbd_ioctl(sc->kbd, cmd, data);
1411 if (error == ENOIOCTL)
1412 error = ENODEV;
2efb75f3 1413 lwkt_reltoken(&vga_token);
984263bc
MD
1414 return error;
1415
984263bc
MD
1416 case KDSKBMODE: /* set keyboard mode */
1417 switch (*(int *)data) {
1418 case K_XLATE: /* switch to XLT ascii mode */
1419 case K_RAW: /* switch to RAW scancode mode */
1420 case K_CODE: /* switch to CODE mode */
1421 scp->kbd_mode = *(int *)data;
1422 if (scp == sc->cur_scp)
1423 kbd_ioctl(sc->kbd, cmd, data);
2efb75f3 1424 lwkt_reltoken(&vga_token);
984263bc
MD
1425 return 0;
1426 default:
2efb75f3 1427 lwkt_reltoken(&vga_token);
984263bc
MD
1428 return EINVAL;
1429 }
1430 /* NOT REACHED */
1431
1432 case KDGKBMODE: /* get keyboard mode */
1433 *(int *)data = scp->kbd_mode;
2efb75f3 1434 lwkt_reltoken(&vga_token);
984263bc
MD
1435 return 0;
1436
1437 case KDGKBINFO:
1438 error = kbd_ioctl(sc->kbd, cmd, data);
1439 if (error == ENOIOCTL)
1440 error = ENODEV;
2efb75f3 1441 lwkt_reltoken(&vga_token);
984263bc
MD
1442 return error;
1443
1444 case KDMKTONE: /* sound the bell */
bd1cd9c2 1445 syscons_lock();
984263bc
MD
1446 if (*(int*)data)
1447 sc_bell(scp, (*(int*)data)&0xffff,
1448 (((*(int*)data)>>16)&0xffff)*hz/1000);
1449 else
1450 sc_bell(scp, scp->bell_pitch, scp->bell_duration);
bd1cd9c2 1451 syscons_unlock();
2efb75f3 1452 lwkt_reltoken(&vga_token);
984263bc
MD
1453 return 0;
1454
1455 case KIOCSOUND: /* make tone (*data) hz */
bd1cd9c2 1456 syscons_lock();
984263bc 1457 if (scp == sc->cur_scp) {
22ff886e 1458 if (*(int *)data) {
bd1cd9c2 1459 error = sc_tone(*(int *)data);
22ff886e 1460 } else {
bd1cd9c2 1461 error = sc_tone(0);
22ff886e 1462 }
bd1cd9c2
MD
1463 } else {
1464 error = 0;
984263bc 1465 }
bd1cd9c2 1466 syscons_unlock();
2efb75f3 1467 lwkt_reltoken(&vga_token);
bd1cd9c2 1468 return error;
984263bc
MD
1469
1470 case KDGKBTYPE: /* get keyboard type */
1471 error = kbd_ioctl(sc->kbd, cmd, data);
1472 if (error == ENOIOCTL) {
1473 /* always return something? XXX */
1474 *(int *)data = 0;
1475 }
2efb75f3 1476 lwkt_reltoken(&vga_token);
984263bc
MD
1477 return 0;
1478
1479 case KDSETLED: /* set keyboard LED status */
22ff886e 1480 if (*(int *)data & ~LED_MASK) { /* FIXME: LOCK_MASK? */
2efb75f3 1481 lwkt_reltoken(&vga_token);
984263bc 1482 return EINVAL;
22ff886e 1483 }
bd1cd9c2 1484 syscons_lock();
984263bc
MD
1485 scp->status &= ~LED_MASK;
1486 scp->status |= *(int *)data;
bd1cd9c2 1487 syscons_unlock();
984263bc
MD
1488 if (scp == sc->cur_scp)
1489 update_kbd_leds(scp, scp->status);
2efb75f3 1490 lwkt_reltoken(&vga_token);
984263bc
MD
1491 return 0;
1492
1493 case KDGETLED: /* get keyboard LED status */
1494 if (scp == sc->cur_scp)
f6ce8b19 1495 save_kbd_state(scp, FALSE);
984263bc 1496 *(int *)data = scp->status & LED_MASK;
2efb75f3 1497 lwkt_reltoken(&vga_token);
984263bc
MD
1498 return 0;
1499
bcc53404
AH
1500 case KBADDKBD: /* add/remove keyboard to/from mux */
1501 case KBRELKBD:
1502 error = kbd_ioctl(sc->kbd, cmd, data);
1503 if (error == ENOIOCTL)
1504 error = ENODEV;
2efb75f3 1505 lwkt_reltoken(&vga_token);
bcc53404
AH
1506 return error;
1507
984263bc
MD
1508 case CONS_SETKBD: /* set the new keyboard */
1509 {
1510 keyboard_t *newkbd;
1511
984263bc
MD
1512 newkbd = kbd_get_keyboard(*(int *)data);
1513 if (newkbd == NULL) {
2efb75f3 1514 lwkt_reltoken(&vga_token);
984263bc
MD
1515 return EINVAL;
1516 }
1517 error = 0;
1518 if (sc->kbd != newkbd) {
1519 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1520 (void *)&sc->keyboard, sckbdevent, sc);
1521 /* i == newkbd->kb_index */
1522 if (i >= 0) {
1523 if (sc->kbd != NULL) {
f6ce8b19 1524 save_kbd_state(sc->cur_scp, FALSE);
984263bc
MD
1525 kbd_release(sc->kbd, (void *)&sc->keyboard);
1526 }
bd1cd9c2 1527 syscons_lock();
984263bc
MD
1528 sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1529 sc->keyboard = i;
bd1cd9c2 1530 syscons_unlock();
984263bc
MD
1531 kbd_ioctl(sc->kbd, KDSKBMODE,
1532 (caddr_t)&sc->cur_scp->kbd_mode);
1533 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
f6ce8b19 1534 LOCK_MASK, FALSE);
984263bc
MD
1535 } else {
1536 error = EPERM; /* XXX */
1537 }
1538 }
2efb75f3 1539 lwkt_reltoken(&vga_token);
984263bc
MD
1540 return error;
1541 }
1542
1543 case CONS_RELKBD: /* release the current keyboard */
984263bc
MD
1544 error = 0;
1545 if (sc->kbd != NULL) {
f6ce8b19 1546 save_kbd_state(sc->cur_scp, FALSE);
984263bc
MD
1547 error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1548 if (error == 0) {
bd1cd9c2 1549 syscons_lock();
984263bc
MD
1550 sc->kbd = NULL;
1551 sc->keyboard = -1;
bd1cd9c2 1552 syscons_unlock();
984263bc
MD
1553 }
1554 }
2efb75f3 1555 lwkt_reltoken(&vga_token);
984263bc
MD
1556 return error;
1557
1558 case CONS_GETTERM: /* get the current terminal emulator info */
1559 {
1560 sc_term_sw_t *sw;
1561
1562 if (((term_info_t *)data)->ti_index == 0) {
1563 sw = scp->tsw;
1564 } else {
1565 sw = sc_term_match_by_number(((term_info_t *)data)->ti_index);
1566 }
1567 if (sw != NULL) {
1568 strncpy(((term_info_t *)data)->ti_name, sw->te_name,
1569 sizeof(((term_info_t *)data)->ti_name));
1570 strncpy(((term_info_t *)data)->ti_desc, sw->te_desc,
1571 sizeof(((term_info_t *)data)->ti_desc));
1572 ((term_info_t *)data)->ti_flags = 0;
2efb75f3 1573 lwkt_reltoken(&vga_token);
984263bc
MD
1574 return 0;
1575 } else {
1576 ((term_info_t *)data)->ti_name[0] = '\0';
1577 ((term_info_t *)data)->ti_desc[0] = '\0';
1578 ((term_info_t *)data)->ti_flags = 0;
2efb75f3 1579 lwkt_reltoken(&vga_token);
984263bc
MD
1580 return EINVAL;
1581 }
1582 }
1583
1584 case CONS_SETTERM: /* set the current terminal emulator */
bd1cd9c2 1585 syscons_lock();
984263bc
MD
1586 error = sc_init_emulator(scp, ((term_info_t *)data)->ti_name);
1587 /* FIXME: what if scp == sc_console! XXX */
bd1cd9c2 1588 syscons_unlock();
2efb75f3 1589 lwkt_reltoken(&vga_token);
984263bc
MD
1590 return error;
1591
1592 case GIO_SCRNMAP: /* get output translation table */
1593 bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
2efb75f3 1594 lwkt_reltoken(&vga_token);
984263bc
MD
1595 return 0;
1596
1597 case PIO_SCRNMAP: /* set output translation table */
1598 bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1599 for (i=0; i<sizeof(sc->scr_map); i++) {
1600 sc->scr_rmap[sc->scr_map[i]] = i;
1601 }
2efb75f3 1602 lwkt_reltoken(&vga_token);
984263bc
MD
1603 return 0;
1604
1605 case GIO_KEYMAP: /* get keyboard translation table */
1606 case PIO_KEYMAP: /* set keyboard translation table */
1607 case GIO_DEADKEYMAP: /* get accent key translation table */
1608 case PIO_DEADKEYMAP: /* set accent key translation table */
1609 case GETFKEY: /* get function key string */
1610 case SETFKEY: /* set function key string */
1611 error = kbd_ioctl(sc->kbd, cmd, data);
1612 if (error == ENOIOCTL)
1613 error = ENODEV;
2efb75f3 1614 lwkt_reltoken(&vga_token);
984263bc
MD
1615 return error;
1616
1617#ifndef SC_NO_FONT_LOADING
1618
1619 case PIO_FONT8x8: /* set 8x8 dot font */
2b5f463d 1620 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1621 lwkt_reltoken(&vga_token);
984263bc 1622 return ENXIO;
22ff886e 1623 }
bd1cd9c2 1624 syscons_lock();
984263bc
MD
1625 bcopy(data, sc->font_8, 8*256);
1626 sc->fonts_loaded |= FONT_8;
1627 /*
1628 * FONT KLUDGE
1629 * Always use the font page #0. XXX
1630 * Don't load if the current font size is not 8x8.
1631 */
2b5f463d
IV
1632 if (sc->fbi == NULL
1633 && ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_height < 14)) {
984263bc 1634 sc_load_font(sc->cur_scp, 0, 8, sc->font_8, 0, 256);
2b5f463d 1635 }
bd1cd9c2 1636 syscons_unlock();
2efb75f3 1637 lwkt_reltoken(&vga_token);
984263bc
MD
1638 return 0;
1639
1640 case GIO_FONT8x8: /* get 8x8 dot font */
2b5f463d 1641 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1642 lwkt_reltoken(&vga_token);
984263bc 1643 return ENXIO;
22ff886e 1644 }
984263bc
MD
1645 if (sc->fonts_loaded & FONT_8) {
1646 bcopy(sc->font_8, data, 8*256);
2efb75f3 1647 lwkt_reltoken(&vga_token);
984263bc
MD
1648 return 0;
1649 }
22ff886e 1650 else {
2efb75f3 1651 lwkt_reltoken(&vga_token);
984263bc 1652 return ENXIO;
22ff886e 1653 }
984263bc
MD
1654
1655 case PIO_FONT8x14: /* set 8x14 dot font */
2b5f463d 1656 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1657 lwkt_reltoken(&vga_token);
984263bc 1658 return ENXIO;
22ff886e 1659 }
bd1cd9c2 1660 syscons_lock();
984263bc
MD
1661 bcopy(data, sc->font_14, 14*256);
1662 sc->fonts_loaded |= FONT_14;
1663 /*
1664 * FONT KLUDGE
1665 * Always use the font page #0. XXX
1666 * Don't load if the current font size is not 8x14.
1667 */
2b5f463d
IV
1668 if (sc->fbi == NULL
1669 && ISTEXTSC(sc->cur_scp)
219917ca
SW
1670 && (sc->cur_scp->font_height >= 14)
1671 && (sc->cur_scp->font_height < 16)) {
984263bc 1672 sc_load_font(sc->cur_scp, 0, 14, sc->font_14, 0, 256);
bd1cd9c2
MD
1673 }
1674 syscons_unlock();
2efb75f3 1675 lwkt_reltoken(&vga_token);
984263bc
MD
1676 return 0;
1677
1678 case GIO_FONT8x14: /* get 8x14 dot font */
2b5f463d 1679 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1680 lwkt_reltoken(&vga_token);
984263bc 1681 return ENXIO;
22ff886e 1682 }
984263bc
MD
1683 if (sc->fonts_loaded & FONT_14) {
1684 bcopy(sc->font_14, data, 14*256);
2efb75f3 1685 lwkt_reltoken(&vga_token);
984263bc
MD
1686 return 0;
1687 }
22ff886e 1688 else {
2efb75f3 1689 lwkt_reltoken(&vga_token);
984263bc 1690 return ENXIO;
22ff886e 1691 }
984263bc
MD
1692
1693 case PIO_FONT8x16: /* set 8x16 dot font */
2b5f463d 1694 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1695 lwkt_reltoken(&vga_token);
984263bc 1696 return ENXIO;
22ff886e 1697 }
bd1cd9c2 1698 syscons_lock();
984263bc
MD
1699 bcopy(data, sc->font_16, 16*256);
1700 sc->fonts_loaded |= FONT_16;
1701 /*
1702 * FONT KLUDGE
1703 * Always use the font page #0. XXX
1704 * Don't load if the current font size is not 8x16.
1705 */
2b5f463d
IV
1706 if (sc->fbi == NULL
1707 && ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_height >= 16)) {
984263bc 1708 sc_load_font(sc->cur_scp, 0, 16, sc->font_16, 0, 256);
2b5f463d 1709 }
bd1cd9c2 1710 syscons_unlock();
2efb75f3 1711 lwkt_reltoken(&vga_token);
984263bc
MD
1712 return 0;
1713
1714 case GIO_FONT8x16: /* get 8x16 dot font */
2b5f463d 1715 if (sc->fbi == NULL && !ISFONTAVAIL(sc->adp->va_flags)) {
2efb75f3 1716 lwkt_reltoken(&vga_token);
984263bc 1717 return ENXIO;
22ff886e 1718 }
984263bc
MD
1719 if (sc->fonts_loaded & FONT_16) {
1720 bcopy(sc->font_16, data, 16*256);
2efb75f3 1721 lwkt_reltoken(&vga_token);
984263bc
MD
1722 return 0;
1723 }
22ff886e 1724 else {
2efb75f3 1725 lwkt_reltoken(&vga_token);
984263bc 1726 return ENXIO;
22ff886e 1727 }
984263bc
MD
1728
1729#endif /* SC_NO_FONT_LOADING */
1730
1731 default:
1732 break;
1733 }
1734
2efb75f3 1735 lwkt_gettoken(&tp->t_token);
fef8985e 1736 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, ap->a_cred);
22ff886e 1737 if (error != ENOIOCTL) {
2efb75f3
MD
1738 lwkt_reltoken(&tp->t_token);
1739 lwkt_reltoken(&vga_token);
1740
984263bc 1741 return(error);
22ff886e 1742 }
2efb75f3 1743
984263bc 1744 error = ttioctl(tp, cmd, data, flag);
22ff886e 1745 if (error != ENOIOCTL) {
2efb75f3
MD
1746 lwkt_reltoken(&tp->t_token);
1747 lwkt_reltoken(&vga_token);
1748
984263bc 1749 return(error);
22ff886e 1750 }
2efb75f3
MD
1751
1752 lwkt_reltoken(&tp->t_token);
1753 lwkt_reltoken(&vga_token);
1754
984263bc
MD
1755 return(ENOTTY);
1756}
1757
1758static void
1759scstart(struct tty *tp)
1760{
1761 struct clist *rbp;
6bc31f17 1762 int len;
984263bc
MD
1763 u_char buf[PCBURST];
1764 scr_stat *scp = SC_STAT(tp->t_dev);
1765
82d1ed25 1766 syscons_lock();
2123da6d
CP
1767 if (scp->status & SLKED ||
1768 (scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
82d1ed25
MD
1769 {
1770 syscons_unlock();
984263bc 1771 return;
82d1ed25 1772 }
984263bc
MD
1773 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1774 tp->t_state |= TS_BUSY;
1775 rbp = &tp->t_outq;
1776 while (rbp->c_cc) {
4725869b 1777 len = clist_qtob(rbp, buf, PCBURST);
984263bc 1778 sc_puts(scp, buf, len);
984263bc
MD
1779 }
1780 tp->t_state &= ~TS_BUSY;
4cdde1a1 1781 syscons_unlock();
984263bc 1782 ttwwakeup(tp);
4cdde1a1
MD
1783 } else {
1784 syscons_unlock();
984263bc 1785 }
984263bc
MD
1786}
1787
1788static void
1789sccnprobe(struct consdev *cp)
1790{
984263bc
MD
1791 int unit;
1792 int flags;
1793
1794 cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1795
1796 /* a video card is always required */
428805e9 1797 if (probe_efi_fb(1) != 0 && !scvidprobe(unit, flags, TRUE))
984263bc
MD
1798 cp->cn_pri = CN_DEAD;
1799
1800 /* syscons will become console even when there is no keyboard */
1801 sckbdprobe(unit, flags, TRUE);
1802
22ff886e 1803 if (cp->cn_pri == CN_DEAD) {
984263bc 1804 return;
22ff886e 1805 }
984263bc
MD
1806
1807 /* initialize required fields */
ce81f184 1808 cp->cn_probegood = 1;
984263bc
MD
1809}
1810
1811static void
1812sccninit(struct consdev *cp)
1813{
984263bc
MD
1814 int unit;
1815 int flags;
1816
1817 sc_get_cons_priority(&unit, &flags);
1818 scinit(unit, flags | SC_KERNEL_CONSOLE);
1819 sc_console_unit = unit;
ce81f184
MD
1820 sc_console = sc_get_softc(unit, SC_KERNEL_CONSOLE)->console_scp;
1821}
1822
1823static void
1824sccninit_fini(struct consdev *cp)
1825{
cd29885a
MD
1826 if (cctl_dev == NULL)
1827 kprintf("sccninit_fini: WARNING: cctl_dev is NULL!\n");
1828 cp->cn_dev = cctl_dev;
984263bc
MD
1829}
1830
fb3cf125
MD
1831/*
1832 * This is called when the console is switched away from syscons to
1833 * a late-configuring device (such as a PCIe serial port). Since
1834 * late-configuring devices basically didn't exist until now, this
1835 * routine was never called, and SURPRISE! It doesn't work... causes
1836 * syscons to implode due to all the funny console-not-console structure
1837 * selection syscons does.
1838 *
1839 * Make it a NOP. Just leave the console designation intact, even
1840 * though it is no longer a console.
1841 */
984263bc
MD
1842static void
1843sccnterm(struct consdev *cp)
1844{
fb3cf125 1845#if 0
984263bc
MD
1846 /* we are not the kernel console any more, release everything */
1847
1848 if (sc_console_unit < 0)
1849 return; /* shouldn't happen */
1850
984263bc 1851#if 0 /* XXX */
bd1cd9c2 1852 syscons_lock();
984263bc
MD
1853 sc_clear_screen(sc_console);
1854 sccnupdate(sc_console);
bd1cd9c2 1855 syscons_unlock();
984263bc
MD
1856#endif
1857 scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1858 sc_console_unit = -1;
1859 sc_console = NULL;
fb3cf125 1860#endif
984263bc
MD
1861}
1862
fc9700a1
MD
1863/*
1864 * Console path - cannot block!
1865 */
984263bc 1866static void
ce81f184 1867sccnputc(void *private, int c)
984263bc
MD
1868{
1869 u_char buf[1];
1870 scr_stat *scp = sc_console;
1871 void *save;
1872#ifndef SC_NO_HISTORY
bd1cd9c2 1873#if 0
984263bc 1874 struct tty *tp;
bd1cd9c2 1875#endif
984263bc 1876#endif /* !SC_NO_HISTORY */
984263bc
MD
1877
1878 /* assert(sc_console != NULL) */
1879
82d1ed25 1880 syscons_lock();
984263bc
MD
1881#ifndef SC_NO_HISTORY
1882 if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1883 scp->status &= ~SLKED;
bd1cd9c2
MD
1884#if 0
1885 /* This can block, illegal in the console path */
f6ce8b19 1886 update_kbd_state(scp, scp->status, SLKED, TRUE);
bd1cd9c2 1887#endif
984263bc
MD
1888 if (scp->status & BUFFER_SAVED) {
1889 if (!sc_hist_restore(scp))
1890 sc_remove_cutmarking(scp);
1891 scp->status &= ~BUFFER_SAVED;
1892 scp->status |= CURSOR_ENABLED;
1893 sc_draw_cursor_image(scp);
1894 }
bd1cd9c2 1895#if 0
984263bc 1896 tp = VIRTUAL_TTY(scp->sc, scp->index);
bd1cd9c2 1897 /* This can block, illegal in the console path */
82d1ed25 1898 if (ISTTYOPEN(tp)) {
984263bc 1899 scstart(tp);
82d1ed25 1900 }
bd1cd9c2 1901#endif
984263bc
MD
1902 }
1903#endif /* !SC_NO_HISTORY */
1904
1905 save = scp->ts;
1906 if (kernel_console_ts != NULL)
1907 scp->ts = kernel_console_ts;
1908 buf[0] = c;
1909 sc_puts(scp, buf, 1);
1910 scp->ts = save;
1911
984263bc 1912 sccnupdate(scp);
82d1ed25 1913 syscons_unlock();
984263bc
MD
1914}
1915
fc9700a1
MD
1916/*
1917 * Console path - cannot block!
1918 */
984263bc 1919static int
ce81f184 1920sccngetc(void *private)
984263bc
MD
1921{
1922 return sccngetch(0);
1923}
1924
fc9700a1
MD
1925/*
1926 * Console path - cannot block!
1927 */
984263bc 1928static int
ce81f184 1929sccncheckc(void *private)
984263bc
MD
1930{
1931 return sccngetch(SCGETC_NONBLOCK);
1932}
1933
ce7866b8
MD
1934/*
1935 * Set polling mode (also disables the tty feed), use when
1936 * polling for console key input.
1937 */
1938static void
1939sccnpoll(void *private, int on)
1940{
1941 scr_stat *scp;
1942
1943 syscons_lock();
1944 sc_touch_scrn_saver();
1945 scp = sc_console->sc->cur_scp; /* XXX */
1946 syscons_unlock();
1947 if (scp->sc->kbd)
1948 kbd_poll(scp->sc->kbd, on);
1949}
1950
984263bc 1951static void
ce81f184 1952sccndbctl(void *private, int on)
984263bc
MD
1953{
1954 /* assert(sc_console_unit >= 0) */
1955 /* try to switch to the kernel console screen */
1956 if (on && debugger == 0) {
1957 /*
1958 * TRY to make sure the screen saver is stopped,
1959 * and the screen is updated before switching to
1960 * the vty0.
1961 */
1962 scrn_timer(NULL);
1963 if (!cold
1964 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
1965 && sc_console->smode.mode == VT_AUTO) {
1966 sc_console->sc->cur_scp->status |= MOUSE_HIDDEN;
bd1cd9c2 1967 syscons_lock();
984263bc 1968 sc_switch_scr(sc_console->sc, sc_console->index);
bd1cd9c2 1969 syscons_unlock();
984263bc
MD
1970 }
1971 }
1972 if (on)
1973 ++debugger;
1974 else
1975 --debugger;
1976}
1977
fc9700a1
MD
1978/*
1979 * Console path - cannot block!
1980 */
984263bc
MD
1981static int
1982sccngetch(int flags)
1983{
1984 static struct fkeytab fkey;
1985 static int fkeycp;
1986 scr_stat *scp;
1987 u_char *p;
1988 int cur_mode;
984263bc
MD
1989 int c;
1990
82d1ed25 1991 syscons_lock();
984263bc
MD
1992 /* assert(sc_console != NULL) */
1993
1994 /*
1995 * Stop the screen saver and update the screen if necessary.
1996 * What if we have been running in the screen saver code... XXX
1997 */
1998 sc_touch_scrn_saver();
1999 scp = sc_console->sc->cur_scp; /* XXX */
2000 sccnupdate(scp);
82d1ed25 2001 syscons_unlock();
984263bc 2002
22ff886e 2003 if (fkeycp < fkey.len) {
984263bc 2004 return fkey.str[fkeycp++];
22ff886e 2005 }
984263bc 2006
22ff886e 2007 if (scp->sc->kbd == NULL) {
984263bc 2008 return -1;
22ff886e 2009 }
984263bc
MD
2010
2011 /*
2012 * Make sure the keyboard is accessible even when the kbd device
2013 * driver is disabled.
2014 */
82d1ed25 2015 crit_enter();
984263bc
MD
2016 kbd_enable(scp->sc->kbd);
2017
2018 /* we shall always use the keyboard in the XLATE mode here */
2019 cur_mode = scp->kbd_mode;
2020 scp->kbd_mode = K_XLATE;
2021 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2022
984263bc 2023 c = scgetc(scp->sc, SCGETC_CN | flags);
984263bc
MD
2024
2025 scp->kbd_mode = cur_mode;
2026 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2027 kbd_disable(scp->sc->kbd);
6bc31f17 2028 crit_exit();
984263bc
MD
2029
2030 switch (KEYFLAGS(c)) {
2031 case 0: /* normal char */
2032 return KEYCHAR(c);
2033 case FKEY: /* function key */
2034 p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
2035 fkey.len = fkeycp;
2036 if ((p != NULL) && (fkey.len > 0)) {
2037 bcopy(p, fkey.str, fkey.len);
2038 fkeycp = 1;
2039 return fkey.str[0];
2040 }
2041 return c; /* XXX */
2042 case NOKEY:
ce7866b8
MD
2043 if (flags & SCGETC_NONBLOCK)
2044 return c;
2045 /* fall through */
984263bc
MD
2046 case ERRKEY:
2047 default:
2048 return -1;
2049 }
2050 /* NOT REACHED */
2051}
2052
2053static void
2054sccnupdate(scr_stat *scp)
2055{
f59df058
SW
2056 int ddb_active;
2057
2058#ifdef DDB
2059 ddb_active = db_active;
2060#else
2061 ddb_active = 0;
2062#endif
2063
984263bc
MD
2064 /* this is a cut-down version of scrn_timer()... */
2065
539fbd92
MD
2066 /*
2067 * Don't update if videoio is in progress. However, if we are paniced
6dfdabab
MD
2068 * or in the debugger it is possible that the variables might be stuck,
2069 * so ignore it in such cases.
539fbd92 2070 */
22ff886e 2071 if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress) {
f59df058 2072 if (panicstr == NULL && ddb_active == 0 && shutdown_in_progress == 0)
539fbd92 2073 return;
22ff886e 2074 }
984263bc 2075
f59df058 2076 if (debugger > 0 || panicstr || ddb_active || shutdown_in_progress) {
984263bc
MD
2077 sc_touch_scrn_saver();
2078 } else if (scp != scp->sc->cur_scp) {
2079 return;
2080 }
2081
2082 if (!run_scrn_saver)
2083 scp->sc->flags &= ~SC_SCRN_IDLE;
2084#if NSPLASH > 0
1758f306
MD
2085 /*
2086 * This is a hard path, we cannot call stop_scrn_saver() here.
2087 */
984263bc 2088 if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1758f306
MD
2089 if (scp->sc->flags & SC_SCRN_BLANKED) {
2090 sc_touch_scrn_saver();
2091 /*stop_scrn_saver(scp->sc, current_saver);*/
2092 }
984263bc
MD
2093#endif /* NSPLASH */
2094
2095 if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
22ff886e 2096 || scp->sc->switch_in_progress) {
984263bc 2097 return;
22ff886e 2098 }
6dfdabab 2099
984263bc
MD
2100 /*
2101 * FIXME: unlike scrn_timer(), we call scrn_update() from here even
2102 * when write_in_progress is non-zero. XXX
2103 */
984263bc 2104 if (!ISGRAPHSC(scp) && !(scp->sc->flags & SC_SCRN_BLANKED))
7ae6dbf0 2105 scrn_update(scp, TRUE, SCRN_ASYNCOK);
984263bc
MD
2106}
2107
2108static void
2109scrn_timer(void *arg)
2110{
2111 static int kbd_interval = 0;
2112 struct timeval tv;
2113 sc_softc_t *sc;
2114 scr_stat *scp;
2115 int again;
984263bc 2116
cbfc8ecb
MD
2117 /*
2118 * Setup depending on who called us
2119 */
984263bc 2120 again = (arg != NULL);
22ff886e 2121 if (arg != NULL) {
984263bc 2122 sc = (sc_softc_t *)arg;
22ff886e 2123 } else if (sc_console != NULL) {
984263bc 2124 sc = sc_console->sc;
22ff886e 2125 } else {
984263bc 2126 return;
22ff886e 2127 }
984263bc 2128
cbfc8ecb
MD
2129 /*
2130 * Don't do anything when we are performing some I/O operations.
2131 * (These are initiated by the frontend?)
2132 */
984263bc
MD
2133 if (sc->font_loading_in_progress || sc->videoio_in_progress) {
2134 if (again)
356bb9cd 2135 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
984263bc
MD
2136 return;
2137 }
984263bc 2138
cbfc8ecb
MD
2139 /*
2140 * Try to allocate a keyboard automatically
2141 */
984263bc 2142 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
984263bc 2143 if (++kbd_interval >= 25) {
bcc53404 2144 sc->keyboard = sc_allocate_keyboard(sc, -1);
984263bc
MD
2145 if (sc->keyboard >= 0) {
2146 sc->kbd = kbd_get_keyboard(sc->keyboard);
2147 kbd_ioctl(sc->kbd, KDSKBMODE,
2148 (caddr_t)&sc->cur_scp->kbd_mode);
2149 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
f6ce8b19 2150 LOCK_MASK, FALSE);
984263bc
MD
2151 }
2152 kbd_interval = 0;
2153 }
2154 }
2155
cbfc8ecb
MD
2156 /*
2157 * Should we stop the screen saver? We need the syscons_lock
2158 * for most of this stuff.
2159 */
984263bc 2160 getmicrouptime(&tv);
cbfc8ecb 2161
bd1cd9c2
MD
2162 if (syscons_lock_nonblock() != 0) {
2163 /* failed to get the lock */
cbfc8ecb
MD
2164 if (again)
2165 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
cbfc8ecb
MD
2166 return;
2167 }
bd1cd9c2 2168 /* successful lock */
cbfc8ecb 2169
984263bc
MD
2170 if (debugger > 0 || panicstr || shutdown_in_progress)
2171 sc_touch_scrn_saver();
2172 if (run_scrn_saver) {
2173 if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
2174 sc->flags |= SC_SCRN_IDLE;
2175 else
2176 sc->flags &= ~SC_SCRN_IDLE;
2177 } else {
2178 sc->scrn_time_stamp = tv.tv_sec;
2179 sc->flags &= ~SC_SCRN_IDLE;
2180 if (scrn_blank_time > 0)
2181 run_scrn_saver = TRUE;
2182 }
2183#if NSPLASH > 0
1743eeb4
IV
2184 if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE)) {
2185 if ((sc->flags & SC_SCRN_BLANKED) && !ISGRAPHSC(sc->cur_scp))
984263bc 2186 stop_scrn_saver(sc, current_saver);
1743eeb4 2187 }
984263bc
MD
2188#endif /* NSPLASH */
2189
2190 /* should we just return ? */
cbfc8ecb
MD
2191 if (sc->blink_in_progress || sc->switch_in_progress ||
2192 sc->write_in_progress)
2193 {
2194 syscons_unlock();
984263bc 2195 if (again)
356bb9cd 2196 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
984263bc
MD
2197 return;
2198 }
2199
2200 /* Update the screen */
2201 scp = sc->cur_scp; /* cur_scp may have changed... */
2202 if (!ISGRAPHSC(scp) && !(sc->flags & SC_SCRN_BLANKED))
7ae6dbf0 2203 scrn_update(scp, TRUE, SCRN_ASYNCOK);
984263bc
MD
2204
2205#if NSPLASH > 0
2206 /* should we activate the screen saver? */
2207 if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
2208 if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
2209 (*current_saver)(sc, TRUE);
2210#endif /* NSPLASH */
2211
cbfc8ecb 2212 syscons_unlock();
984263bc 2213 if (again)
356bb9cd 2214 callout_reset(&sc->scrn_timer_ch, hz / 25, scrn_timer, sc);
984263bc
MD
2215}
2216
2217static int
2218and_region(int *s1, int *e1, int s2, int e2)
2219{
2220 if (*e1 < s2 || e2 < *s1)
2221 return FALSE;
2222 *s1 = imax(*s1, s2);
2223 *e1 = imin(*e1, e2);
2224 return TRUE;
2225}
2226
a6aa3935 2227/*
7ae6dbf0
MD
2228 * Refresh modified frame buffer range. Also used to
2229 * scroll (entire FB is marked modified).
2230 *
2231 * This function is allowed to run without the syscons_lock,
2232 * so scp fields can change unexpected. We cache most values
2233 * that we care about and silently discard illegal ranges.
a6aa3935 2234 */
984263bc 2235static void
7ae6dbf0 2236scrn_update(scr_stat *scp, int show_cursor, int flags)
984263bc
MD
2237{
2238 int start;
2239 int end;
539fbd92
MD
2240 int cpos;
2241 int copos;
984263bc
MD
2242 int s;
2243 int e;
f59df058
SW
2244 int ddb_active;
2245
2246#ifdef DDB
2247 ddb_active = db_active;
2248#else
2249 ddb_active = 0;
2250#endif
984263bc 2251
7ae6dbf0 2252 /*
539fbd92
MD
2253 * Try to run large screen updates as an async operation, which will
2254 * call this function again from a thread with BULKUNLOCK set, allowing
2255 * interrupts during the update which tends to make the system behave
2256 * better (no sound glitches, etc).
7ae6dbf0 2257 */
b2208254 2258 if ((flags & SCRN_ASYNCOK) && syscons_async && scp->asynctd &&
7ae6dbf0 2259 (scp->end - scp->start) > 16 &&
f59df058 2260 panicstr == NULL && ddb_active == 0 && shutdown_in_progress == 0) {
7ae6dbf0
MD
2261 scp->show_cursor = show_cursor;
2262 scp->queue_update_td = 1;
2263 wakeup(&scp->asynctd);
2264 return;
2265 }
2266 if (flags & SCRN_BULKUNLOCK)
2267 syscons_lock();
2268
2269 /*
2270 * Synchronous operation or called from
2271 */
2272
984263bc 2273 /* assert(scp == scp->sc->cur_scp) */
7ae6dbf0 2274 atomic_add_int(&scp->sc->videoio_in_progress, 1);
984263bc 2275
539fbd92
MD
2276 cpos = scp->cursor_pos;
2277 copos = scp->cursor_oldpos;
2278
984263bc
MD
2279#ifndef SC_NO_CUTPASTE
2280 /* remove the previous mouse pointer image if necessary */
2281 if (scp->status & MOUSE_VISIBLE) {
2282 s = scp->mouse_pos;
2283 e = scp->mouse_pos + scp->xsize + 1;
2284 if ((scp->status & (MOUSE_MOVED | MOUSE_HIDDEN))
2285 || and_region(&s, &e, scp->start, scp->end)
2286 || ((scp->status & CURSOR_ENABLED) &&
539fbd92
MD
2287 (cpos != copos) &&
2288 (and_region(&s, &e, cpos, cpos)
2289 || and_region(&s, &e, copos, copos)))) {
984263bc
MD
2290 sc_remove_mouse_image(scp);
2291 if (scp->end >= scp->xsize*scp->ysize)
2292 scp->end = scp->xsize*scp->ysize - 1;
2293 }
2294 }
2295#endif /* !SC_NO_CUTPASTE */
2296
539fbd92
MD
2297 /*
2298 * WARNING: Don't add debugging kprintf()s with syscons locked.
2299 * Or at all.
2300 */
984263bc 2301 if (scp->end >= scp->xsize*scp->ysize) {
984263bc
MD
2302 scp->end = scp->xsize*scp->ysize - 1;
2303 }
2304 if (scp->start < 0) {
984263bc
MD
2305 scp->start = 0;
2306 }
984263bc 2307
7ae6dbf0
MD
2308 /*
2309 * Main update, extract update range and reset
2310 * ASAP.
2311 */
2312 start = scp->start;
2313 end = scp->end;
2314 scp->end = 0;
2315 scp->start = scp->xsize * scp->ysize - 1;
2316
2317 if (start <= end) {
539fbd92
MD
2318 if (flags & SCRN_BULKUNLOCK) {
2319 atomic_add_int(&scp->sc->videoio_in_progress, -1);
7ae6dbf0 2320 syscons_unlock();
539fbd92 2321 }
7ae6dbf0 2322 (*scp->rndr->draw)(scp, start, end - start + 1, FALSE);
539fbd92 2323 if (flags & SCRN_BULKUNLOCK) {
7ae6dbf0 2324 syscons_lock();
539fbd92
MD
2325 atomic_add_int(&scp->sc->videoio_in_progress, 1);
2326 }
7ae6dbf0
MD
2327
2328 /*
2329 * Handle cut sequence
2330 */
2331 s = scp->mouse_cut_start;
2332 e = scp->mouse_cut_end;
2333 cpu_ccfence(); /* allowed to race */
2334
2335 if (e >= 0) {
2336 if (s > e) {
2337 int r = s;
2338 s = e;
2339 e = r;
984263bc 2340 }
984263bc 2341 /* does the cut-mark region overlap with the update region? */
7ae6dbf0 2342 if (and_region(&s, &e, start, end)) {
539fbd92
MD
2343 if (flags & SCRN_BULKUNLOCK) {
2344 atomic_add_int(&scp->sc->videoio_in_progress, -1);
7ae6dbf0 2345 syscons_unlock();
539fbd92 2346 }
7ae6dbf0 2347 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
539fbd92 2348 if (flags & SCRN_BULKUNLOCK) {
7ae6dbf0 2349 syscons_lock();
539fbd92
MD
2350 atomic_add_int(&scp->sc->videoio_in_progress, 1);
2351 }
984263bc 2352 }
984263bc
MD
2353 }
2354 }
2355
2356 /* we are not to show the cursor and the mouse pointer... */
7ae6dbf0
MD
2357 if (!show_cursor)
2358 goto cleanup;
984263bc
MD
2359
2360 /* update cursor image */
b2208254 2361 if (scp->status & CURSOR_ENABLED) {
7ae6dbf0
MD
2362 s = start;
2363 e = end;
984263bc 2364 /* did cursor move since last time ? */
539fbd92 2365 if (cpos != copos) {
984263bc 2366 /* do we need to remove old cursor image ? */
539fbd92 2367 if (!and_region(&s, &e, copos, copos))
984263bc
MD
2368 sc_remove_cursor_image(scp);
2369 sc_draw_cursor_image(scp);
2370 } else {
b2208254 2371 if (s <= e && and_region(&s, &e, cpos, cpos)) {
984263bc
MD
2372 /* cursor didn't move, but has been overwritten */
2373 sc_draw_cursor_image(scp);
b2208254 2374 } else if (scp->sc->flags & SC_BLINK_CURSOR) {
984263bc 2375 /* if it's a blinking cursor, update it */
539fbd92
MD
2376 (*scp->rndr->blink_cursor)(scp, cpos,
2377 sc_inside_cutmark(scp, cpos));
b2208254 2378 }
984263bc
MD
2379 }
2380 }
2381
2382#ifndef SC_NO_CUTPASTE
2383 /* update "pseudo" mouse pointer image */
2384 if (scp->sc->flags & SC_MOUSE_ENABLED) {
2385 if (!(scp->status & (MOUSE_VISIBLE | MOUSE_HIDDEN))) {
2386 scp->status &= ~MOUSE_MOVED;
2387 sc_draw_mouse_image(scp);
2388 }
2389 }
2390#endif /* SC_NO_CUTPASTE */
2391
7ae6dbf0
MD
2392 /*
2393 * Cleanup
2394 */
2395cleanup:
2396 atomic_add_int(&scp->sc->videoio_in_progress, -1);
2397 if (flags & SCRN_BULKUNLOCK)
2398 syscons_unlock();
984263bc
MD
2399}
2400
a6aa3935 2401/*
7ae6dbf0
MD
2402 * Thread handles potentially expensive screen updates. The function is
2403 * expected to operate safely without locks.
a6aa3935 2404 */
7ae6dbf0
MD
2405static void
2406scrn_update_thread(void *arg)
2407{
2408 scr_stat *scp = arg;
2409 for (;;) {
2410 if (scp->queue_update_td == 0) {
2411 tsleep_interlock(&scp->asynctd, 0);
2412 if (scp->queue_update_td == 0)
2413 tsleep(&scp->asynctd, PINTERLOCKED, "wait", 0);
2414 }
2415 scp->queue_update_td = 0;
ba409a88 2416 lockmgr(&sc_asynctd_lk, LK_EXCLUSIVE);
7ae6dbf0
MD
2417 atomic_add_int(&scp->sc->videoio_in_progress, 1);
2418 scrn_update(scp, scp->show_cursor, SCRN_BULKUNLOCK);
2419 atomic_add_int(&scp->sc->videoio_in_progress, -1);
ba409a88 2420 lockmgr(&sc_asynctd_lk, LK_RELEASE);
7ae6dbf0 2421 }
a6aa3935
MD
2422}
2423
ba409a88
IV
2424static void
2425sc_fb_set_par(void *context, int pending)
2426{
2427 sc_softc_t *sc = context;
ba409a88 2428
2efb75f3 2429 lwkt_gettoken(&vga_token);
0d7c8a4d
IV
2430 if (sc->fbi != NULL && sc->fbi->fbops.fb_set_par != NULL)
2431 sc->fbi->fbops.fb_set_par(sc->fbi);
2efb75f3 2432 lwkt_reltoken(&vga_token);
ba409a88
IV
2433}
2434
984263bc 2435#if NSPLASH > 0
f8b03d86
IV
2436static void
2437sc_fb_blank(void *context, int pending)
2438{
2439 sc_softc_t *sc = context;
2440
2efb75f3 2441 lwkt_gettoken(&vga_token);
f8b03d86
IV
2442 if (sc->fbi != NULL && sc->fbi->fbops.fb_blank != NULL) {
2443 /* 0 == FB_BLANK_UNBLANK and 4 == FB_BLANK_POWERDOWN */
43c88c9d 2444 if (sc->flags & SC_SCRN_BLANKED) {
f8b03d86 2445 sc->fbi->fbops.fb_blank(4, sc->fbi);
43c88c9d
IV
2446 sc->fb_blanked = TRUE;
2447 if (sc->unit == sc_console_unit)
2448 cons_unavail = TRUE;
2449 } else {
f8b03d86 2450 sc->fbi->fbops.fb_blank(0, sc->fbi);
43c88c9d
IV
2451 sc->fb_blanked = FALSE;
2452 if (sc->unit == sc_console_unit &&
2453 sc->cur_scp->smode.mode == VT_AUTO)
2454 cons_unavail = FALSE;
2455 }
f8b03d86 2456 }
2efb75f3 2457 lwkt_reltoken(&vga_token);
f8b03d86
IV
2458}
2459
2460static void
2461scframebuffer_saver(sc_softc_t *sc, int show)
2462{
2463 scr_stat *scp = sc->cur_scp;
2464
2465 if (panicstr)
2466 return;
2467
2468 /*
2469 * Gets called on every screen update while screensaver is active,
2470 * so we need to check the SC_SCRN_BLANKED flag ourselves.
2471 */
2472 if ((sc->flags & SC_SCRN_BLANKED) && show)
2473 return;
2474
2475 taskqueue_cancel(taskqueue_thread[0], sc->fb_blank_task, NULL);
2476 crit_enter();
2477 if (show) {
2478 scp->status |= SAVER_RUNNING;
2479 sc->flags |= SC_SCRN_BLANKED;
2480 ++scrn_blanked;
2481 } else {
2482 scp->status &= ~SAVER_RUNNING;
2483 sc->flags &= ~SC_SCRN_BLANKED;
2484 --scrn_blanked;
2485 }
2486 crit_exit();
2487 taskqueue_enqueue(taskqueue_thread[0], sc->fb_blank_task);
2488}
2489
984263bc
MD
2490static int
2491scsplash_callback(int event, void *arg)
2492{
2493 sc_softc_t *sc;
2494 int error;
2495
2496 sc = (sc_softc_t *)arg;
2497
2498 switch (event) {
2499 case SPLASH_INIT:
2500 if (add_scrn_saver(scsplash_saver) == 0) {
2501 sc->flags &= ~SC_SAVER_FAILED;
2502 run_scrn_saver = TRUE;
96a1eea0 2503 if (cold) {
984263bc
MD
2504 scsplash_stick(TRUE);
2505 (*current_saver)(sc, TRUE);
2506 }
2507 }
2508 return 0;
2509
2510 case SPLASH_TERM:
2511 if (current_saver == scsplash_saver) {
2512 scsplash_stick(FALSE);
2513 error = remove_scrn_saver(scsplash_saver);
22ff886e 2514 if (error) {
984263bc 2515 return error;
22ff886e 2516 }
984263bc
MD
2517 }
2518 return 0;
2519
2520 default:
2521 return EINVAL;
2522 }
2523}
2524
2525static void
2526scsplash_saver(sc_softc_t *sc, int show)
2527{
2528 static int busy = FALSE;
2529 scr_stat *scp;
2530
2531 if (busy)
2532 return;
2533 busy = TRUE;
2534
2535 scp = sc->cur_scp;
2536 if (show) {
2537 if (!(sc->flags & SC_SAVER_FAILED)) {
2538 if (!(sc->flags & SC_SCRN_BLANKED))
2539 set_scrn_saver_mode(scp, -1, NULL, 0);
2540 switch (splash(sc->adp, TRUE)) {
2541 case 0: /* succeeded */
2542 break;
2543 case EAGAIN: /* try later */
2544 restore_scrn_saver_mode(scp, FALSE);
2545 sc_touch_scrn_saver(); /* XXX */
2546 break;
2547 default:
2548 sc->flags |= SC_SAVER_FAILED;
2549 scsplash_stick(FALSE);
2550 restore_scrn_saver_mode(scp, TRUE);
e3869ec7 2551 kprintf("scsplash_saver(): failed to put up the image\n");
984263bc
MD
2552 break;
2553 }
2554 }
2555 } else if (!sticky_splash) {
2556 if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
2557 restore_scrn_saver_mode(scp, TRUE);
2558 }
2559 busy = FALSE;
2560}
2561
2562static int
2563add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
2564{
2565#if 0
2566 int error;
2567
2568 if (current_saver != none_saver) {
2569 error = remove_scrn_saver(current_saver);
2570 if (error)
2571 return error;
2572 }
2573#endif
22ff886e 2574 if (current_saver != none_saver) {
984263bc 2575 return EBUSY;
22ff886e 2576 }
984263bc
MD
2577
2578 run_scrn_saver = FALSE;
2579 saver_mode = CONS_LKM_SAVER;
2580 current_saver = this_saver;
2581 return 0;
2582}
2583
2584static int
2585remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
2586{
2587 if (current_saver != this_saver)
2588 return EINVAL;
2589
2590#if 0
2591 /*
2592 * In order to prevent `current_saver' from being called by
2593 * the timeout routine `scrn_timer()' while we manipulate
2594 * the saver list, we shall set `current_saver' to `none_saver'
2595 * before stopping the current saver, rather than blocking by `splXX()'.
2596 */
2597 current_saver = none_saver;
2598 if (scrn_blanked)
2599 stop_scrn_saver(this_saver);
2600#endif
984263bc 2601 /* unblank all blanked screens */
0510b0ee 2602 wait_scrn_saver_stop(NULL, FALSE);
22ff886e 2603 if (scrn_blanked) {
984263bc 2604 return EBUSY;
22ff886e 2605 }
984263bc
MD
2606
2607 current_saver = none_saver;
2608 return 0;
2609}
2610
2611static int
2612set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
2613{
984263bc
MD
2614
2615 /* assert(scp == scp->sc->cur_scp) */
6bc31f17 2616 crit_enter();
984263bc
MD
2617 if (!ISGRAPHSC(scp))
2618 sc_remove_cursor_image(scp);
2619 scp->splash_save_mode = scp->mode;
2620 scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
2621 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
2622 scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
2623 scp->sc->flags |= SC_SCRN_BLANKED;
2624 ++scrn_blanked;
6bc31f17 2625 crit_exit();
22ff886e 2626 if (mode < 0) {
984263bc 2627 return 0;
22ff886e 2628 }
984263bc
MD
2629 scp->mode = mode;
2630 if (set_mode(scp) == 0) {
ba409a88 2631 if (scp->sc->fbi == NULL &&
0e33c40d 2632 scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS) {
984263bc 2633 scp->status |= GRAPHICS_MODE;
0e33c40d 2634 }
ba409a88 2635 if (scp->sc->fbi == NULL && pal != NULL)
984263bc 2636 load_palette(scp->sc->adp, pal);
984263bc
MD
2637 sc_set_border(scp, border);
2638 return 0;
2639 } else {
6bc31f17 2640 crit_enter();
984263bc
MD
2641 scp->mode = scp->splash_save_mode;
2642 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2643 scp->status |= scp->splash_save_status;
6bc31f17 2644 crit_exit();
984263bc
MD
2645 return 1;
2646 }
22ff886e 2647 /* NOTREACHED */
984263bc
MD
2648}
2649
2650static int
2651restore_scrn_saver_mode(scr_stat *scp, int changemode)
2652{
2653 int mode;
2654 int status;
984263bc
MD
2655
2656 /* assert(scp == scp->sc->cur_scp) */
6bc31f17 2657 crit_enter();
984263bc
MD
2658 mode = scp->mode;
2659 status = scp->status;
2660 scp->mode = scp->splash_save_mode;
2661 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2662 scp->status |= scp->splash_save_status;
2663 scp->sc->flags &= ~SC_SCRN_BLANKED;
2664 if (!changemode) {
2665 if (!ISGRAPHSC(scp))
2666 sc_draw_cursor_image(scp);
2667 --scrn_blanked;
6bc31f17 2668 crit_exit();
984263bc
MD
2669 return 0;
2670 }
2671 if (set_mode(scp) == 0) {
ba409a88 2672 if (scp->sc->fbi == NULL)
0e33c40d 2673 load_palette(scp->sc->adp, scp->sc->palette);
984263bc 2674 --scrn_blanked;
6bc31f17 2675 crit_exit();
984263bc
MD
2676 return 0;
2677 } else {
2678 scp->mode = mode;
2679 scp->status = status;
6bc31f17 2680 crit_exit();
984263bc
MD
2681 return 1;
2682 }
22ff886e 2683 /* NOTREACHED */
984263bc
MD
2684}
2685
2686static void
2687stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
2688{
2689 (*saver)(sc, FALSE);
2690 run_scrn_saver = FALSE;
2691 /* the screen saver may have chosen not to stop after all... */
22ff886e 2692 if (sc->flags & SC_SCRN_BLANKED) {
984263bc 2693 return;
22ff886e 2694 }
984263bc
MD
2695
2696 mark_all(sc->cur_scp);
2697 if (sc->delayed_next_scr)
2698 sc_switch_scr(sc, sc->delayed_next_scr - 1);
0510b0ee 2699 wakeup(&scrn_blanked);
984263bc
MD
2700}
2701
2702static int
0510b0ee 2703wait_scrn_saver_stop(sc_softc_t *sc, int need_unlock)
984263bc
MD
2704{
2705 int error = 0;
2706
2707 while (scrn_blanked > 0) {
2708 run_scrn_saver = FALSE;
2709 if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
2710 error = 0;
2711 break;
2712 }
0510b0ee
IV
2713 if (need_unlock) {
2714 tsleep_interlock(&scrn_blanked, PCATCH);
2715 syscons_unlock();
2716 error = tsleep(&scrn_blanked, PCATCH | PINTERLOCKED, "scrsav", 0);
2717 syscons_lock();
2718 } else {
2719 error = tsleep(&scrn_blanked, PCATCH, "scrsav", 0);
2720 }
f3628b86
MD
2721 /* May return ERESTART */
2722 if (error)
2723 break;
984263bc
MD
2724 }
2725 run_scrn_saver = FALSE;
2726 return error;
2727}
2728#endif /* NSPLASH */
2729
8f523d1c
SZ
2730void
2731sc_start_scrn_saver(sc_softc_t *sc)
2732{
2733#if NSPLASH > 0
2734 (*current_saver)(sc, TRUE);
2735#endif
2736}
2737
2738void
2739sc_stop_scrn_saver(sc_softc_t *sc)
2740{
2741#if NSPLASH > 0
2742 if (sc->flags & SC_SCRN_BLANKED)
2743 stop_scrn_saver(sc, current_saver);
2744#endif
2745}
2746
984263bc
MD
2747void
2748sc_touch_scrn_saver(void)
2749{
2750 scsplash_stick(FALSE);
2751 run_scrn_saver = FALSE;
2752}
2753
2754int
2755sc_switch_scr(sc_softc_t *sc, u_int next_scr)
2756{
2757 scr_stat *cur_scp;
2758 struct tty *tp;
984263bc
MD
2759
2760 DPRINTF(5, ("sc0: sc_switch_scr() %d ", next_scr + 1));
2761
2762 /* prevent switch if previously requested */
2763 if (sc->flags & SC_SCRN_VTYLOCK) {
2764 sc_bell(sc->cur_scp, sc->cur_scp->bell_pitch,
2765 sc->cur_scp->bell_duration);
2766 return EPERM;
2767 }
2768
2769 /* delay switch if the screen is blanked or being updated */
2770 if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2771 || sc->blink_in_progress || sc->videoio_in_progress) {
2772 sc->delayed_next_scr = next_scr + 1;
2773 sc_touch_scrn_saver();
2774 DPRINTF(5, ("switch delayed\n"));
2775 return 0;
2776 }
2777
984263bc
MD
2778 cur_scp = sc->cur_scp;
2779
bd1cd9c2
MD
2780 /*
2781 * we are in the middle of the vty switching process...
2782 *
a8d3ab53
MD
2783 * This may be in the console path, be very careful. pfindn() is
2784 * still going to use a spinlock but it no longer uses tokens so
2785 * we should be ok.
bd1cd9c2
MD
2786 */
2787 if (sc->switch_in_progress &&
2788 (cur_scp->smode.mode == VT_PROCESS) &&
a8d3ab53 2789 cur_scp->proc) {
58c2553a 2790 if (cur_scp->proc != pfindn(cur_scp->pid)) {
984263bc
MD
2791 /*
2792 * The controlling process has died!!. Do some clean up.
2793 * NOTE:`cur_scp->proc' and `cur_scp->smode.mode'
2794 * are not reset here yet; they will be cleared later.
2795 */
a8d3ab53 2796 DPRINTF(5, ("cur_scp controlling process %d died, ", cur_scp->pid));
984263bc
MD
2797 if (cur_scp->status & SWITCH_WAIT_REL) {
2798 /*
2799 * Force the previous switch to finish, but return now
2800 * with error.
6bc31f17 2801 *
984263bc
MD
2802 */
2803 DPRINTF(5, ("reset WAIT_REL, "));
6bc31f17 2804 finish_vt_rel(cur_scp, TRUE);
984263bc
MD
2805 DPRINTF(5, ("finishing previous switch\n"));
2806 return EINVAL;
2807 } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2808 /* let's assume screen switch has been completed. */
2809 DPRINTF(5, ("reset WAIT_ACQ, "));
2810 finish_vt_acq(cur_scp);
2811 } else {
2812 /*
2813 * We are in between screen release and acquisition, and
2814 * reached here via scgetc() or scrn_timer() which has
2815 * interrupted exchange_scr(). Don't do anything stupid.
2816 */
2817 DPRINTF(5, ("waiting nothing, "));
2818 }
2819 } else {
2820 /*
2821 * The controlling process is alive, but not responding...
2822 * It is either buggy or it may be just taking time.
2823 * The following code is a gross kludge to cope with this
2824 * problem for which there is no clean solution. XXX
2825 */
2826 if (cur_scp->status & SWITCH_WAIT_REL) {
2827 switch (sc->switch_in_progress++) {
2828 case 1:
2829 break;
2830 case 2:
2831 DPRINTF(5, ("sending relsig again, "));
2832 signal_vt_rel(cur_scp);
2833 break;
2834 case 3:
2835 break;
2836 case 4:
2837 default:
2838 /*
2839 * Act as if the controlling program returned
2840 * VT_FALSE.
6bc31f17 2841 *
984263bc
MD
2842 */
2843 DPRINTF(5, ("force reset WAIT_REL, "));
6bc31f17 2844 finish_vt_rel(cur_scp, FALSE);
984263bc
MD
2845 DPRINTF(5, ("act as if VT_FALSE was seen\n"));
2846 return EINVAL;
2847 }
2848 } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2849 switch (sc->switch_in_progress++) {
2850 case 1:
2851 break;
2852 case 2:
2853 DPRINTF(5, ("sending acqsig again, "));
2854 signal_vt_acq(cur_scp);
2855 break;
2856 case 3:
2857 break;
2858 case 4:
2859 default:
2860 /* clear the flag and finish the previous switch */
2861 DPRINTF(5, ("force reset WAIT_ACQ, "));
2862 finish_vt_acq(cur_scp);
2863 break;
2864 }
2865 }
2866 }
2867 }
2868
2869 /*
2870 * Return error if an invalid argument is given, or vty switch
2871 * is still in progress.
2872 */
2873 if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2874 || sc->switch_in_progress) {
984263bc
MD
2875 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2876 DPRINTF(5, ("error 1\n"));
2877 return EINVAL;
2878 }
2879
2880 /*
2881 * Don't allow switching away from the graphics mode vty
2882 * if the switch mode is VT_AUTO, unless the next vty is the same
2883 * as the current or the current vty has been closed (but showing).
2884 */
2885 tp = VIRTUAL_TTY(sc, cur_scp->index);
2886 if ((cur_scp->index != next_scr)
2887 && ISTTYOPEN(tp)
2888 && (cur_scp->smode.mode == VT_AUTO)
2889 && ISGRAPHSC(cur_scp)) {
984263bc
MD
2890 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2891 DPRINTF(5, ("error, graphics mode\n"));
2892 return EINVAL;
2893 }
2894
2895 /*
2896 * Is the wanted vty open? Don't allow switching to a closed vty.
2897 * If we are in DDB, don't switch to a vty in the VT_PROCESS mode.
2898 * Note that we always allow the user to switch to the kernel
2899 * console even if it is closed.
2900 */
2901 if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2902 tp = VIRTUAL_TTY(sc, next_scr);
2903 if (!ISTTYOPEN(tp)) {
984263bc
MD
2904 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2905 DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2906 return EINVAL;
2907 }
2908 if ((debugger > 0) && (SC_STAT(tp->t_dev)->smode.mode == VT_PROCESS)) {
984263bc
MD
2909 DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n"));
2910 return EINVAL;
2911 }
2912 }
2913
2914 /* this is the start of vty switching process... */
2915 ++sc->switch_in_progress;
2916 sc->delayed_next_scr = 0;
2917 sc->old_scp = cur_scp;
2918 sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2919 if (sc->new_scp == sc->old_scp) {
2920 sc->switch_in_progress = 0;
2921 wakeup((caddr_t)&sc->new_scp->smode);
984263bc
MD
2922 DPRINTF(5, ("switch done (new == old)\n"));
2923 return 0;
2924 }
2925
2926 /* has controlling process died? */
2927 vt_proc_alive(sc->old_scp);
2928 vt_proc_alive(sc->new_scp);
2929
2930 /* wait for the controlling process to release the screen, if necessary */
2931 if (signal_vt_rel(sc->old_scp)) {
984263bc
MD
2932 return 0;
2933 }
2934
2935 /* go set up the new vty screen */
984263bc 2936 exchange_scr(sc);
984263bc
MD
2937
2938 /* wake up processes waiting for this vty */
2939 wakeup((caddr_t)&sc->cur_scp->smode);
2940
2941 /* wait for the controlling process to acknowledge, if necessary */
2942 if (signal_vt_acq(sc->cur_scp)) {
984263bc
MD
2943 return 0;
2944 }
2945
2946 sc->switch_in_progress = 0;
43c88c9d 2947 if (sc->unit == sc_console_unit && !sc->fb_blanked)
984263bc 2948 cons_unavail = FALSE;
984263bc
MD
2949 DPRINTF(5, ("switch done\n"));
2950
2951 return 0;
2952}
2953
6bc31f17
MD
2954static void
2955do_switch_scr(sc_softc_t *sc)
984263bc 2956{
2efb75f3 2957 lwkt_gettoken(&vga_token);
984263bc
MD
2958 vt_proc_alive(sc->new_scp);
2959
984263bc 2960 exchange_scr(sc);
984263bc
MD
2961 /* sc->cur_scp == sc->new_scp */
2962 wakeup((caddr_t)&sc->cur_scp->smode);
2963
2964 /* wait for the controlling process to acknowledge, if necessary */
2965 if (!signal_vt_acq(sc->cur_scp)) {
2966 sc->switch_in_progress = 0;
43c88c9d 2967 if (sc->unit == sc_console_unit && !sc->fb_blanked)
984263bc
MD
2968 cons_unavail = FALSE;
2969 }
2efb75f3 2970 lwkt_reltoken(&vga_token);
984263bc
MD
2971}
2972
2973static int
2974vt_proc_alive(scr_stat *scp)
2975{
2efb75f3 2976 lwkt_gettoken(&vga_token);
984263bc 2977 if (scp->proc) {
58c2553a 2978 if (scp->proc == pfindn(scp->pid)) {
2efb75f3 2979 lwkt_reltoken(&vga_token);
984263bc 2980 return TRUE;
22ff886e 2981 }
984263bc
MD
2982 scp->proc = NULL;
2983 scp->smode.mode = VT_AUTO;
2984 DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2985 }
2efb75f3 2986 lwkt_reltoken(&vga_token);
984263bc
MD
2987 return FALSE;
2988}
2989
2990static int
2991signal_vt_rel(scr_stat *scp)
2992{
a8d3ab53
MD
2993 struct proc *p;
2994
2efb75f3 2995 lwkt_gettoken(&vga_token);
22ff886e 2996 if (scp->smode.mode != VT_PROCESS) {
2efb75f3 2997 lwkt_reltoken(&vga_token);
984263bc 2998 return FALSE;
22ff886e 2999 }
984263bc 3000 scp->status |= SWITCH_WAIT_REL;
a8d3ab53
MD
3001 p = scp->proc;
3002 PHOLD(p);
3003 ksignal(p, scp->smode.relsig);
3004 PRELE(p);
984263bc 3005 DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2efb75f3 3006 lwkt_reltoken(&vga_token);
a8d3ab53 3007
984263bc
MD
3008 return TRUE;
3009}
3010
3011static int
3012signal_vt_acq(scr_stat *scp)
3013{
a8d3ab53
MD
3014 struct proc *p;
3015
2efb75f3 3016 lwkt_gettoken(&vga_token);
22ff886e 3017 if (scp->smode.mode != VT_PROCESS) {
2efb75f3 3018 lwkt_reltoken(&vga_token);
984263bc 3019 return FALSE;
22ff886e 3020 }
984263bc
MD
3021 if (scp->sc->unit == sc_console_unit)
3022 cons_unavail = TRUE;
3023 scp->status |= SWITCH_WAIT_ACQ;
a8d3ab53
MD
3024 p = scp->proc;
3025 PHOLD(p);
3026 ksignal(p, scp->smode.acqsig);
3027 PRELE(p);
984263bc 3028 DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2efb75f3 3029 lwkt_reltoken(&vga_token);
a8d3ab53 3030
984263bc
MD
3031 return TRUE;
3032}
3033
3034static int
6bc31f17 3035finish_vt_rel(scr_stat *scp, int release)
984263bc 3036{
2efb75f3 3037 lwkt_gettoken(&vga_token);
984263bc
MD
3038 if (scp == scp->sc->old_scp && scp->status & SWITCH_WAIT_REL) {
3039 scp->status &= ~SWITCH_WAIT_REL;
3040 if (release)
6bc31f17 3041 do_switch_scr(scp->sc);
984263bc
MD
3042 else
3043 scp->sc->switch_in_progress = 0;
2efb75f3 3044 lwkt_reltoken(&vga_token);
984263bc
MD
3045 return 0;
3046 }
2efb75f3 3047 lwkt_reltoken(&vga_token);
984263bc
MD
3048 return EINVAL;
3049}
3050
3051static int
3052finish_vt_acq(scr_stat *scp)
3053{
2efb75f3 3054 lwkt_gettoken(&vga_token);
984263bc
MD
3055 if (scp == scp->sc->new_scp && scp->status & SWITCH_WAIT_ACQ) {
3056 scp->status &= ~SWITCH_WAIT_ACQ;
3057 scp->sc->switch_in_progress = 0;
2efb75f3 3058 lwkt_reltoken(&vga_token);
984263bc
MD
3059 return 0;
3060 }
2efb75f3 3061 lwkt_reltoken(&vga_token);
984263bc
MD
3062 return EINVAL;
3063}
3064
3065static void
3066exchange_scr(sc_softc_t *sc)
3067{
3068 scr_stat *scp;
3069
2efb75f3 3070 lwkt_gettoken(&vga_token);
984263bc
MD
3071 /* save the current state of video and keyboard */
3072 sc_move_cursor(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
3073 if (!ISGRAPHSC(sc->old_scp))
3074 sc_remove_cursor_image(sc->old_scp);
3075 if (sc->old_scp->kbd_mode == K_XLATE)
f6ce8b19 3076 save_kbd_state(sc->old_scp, TRUE);
984263bc
MD
3077
3078 /* set up the video for the new screen */
3079 scp = sc->cur_scp = sc->new_scp;
3080 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
3081 set_mode(scp);
428805e9 3082 else if (sc->adp != NULL)
984263bc
MD
3083 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3084 (void *)sc->adp->va_window, FALSE);
3085 scp->status |= MOUSE_HIDDEN;
717f4a47 3086 sc_update_render(scp); /* Switch to kms renderer if necessary */
984263bc
MD
3087 sc_move_cursor(scp, scp->xpos, scp->ypos);
3088 if (!ISGRAPHSC(scp))
3089 sc_set_cursor_image(scp);
0e33c40d 3090 if (sc->fbi == NULL && ISGRAPHSC(sc->old_scp))
984263bc 3091 load_palette(sc->adp, sc->palette);
8a5e307d
IV
3092 if (!ISGRAPHSC(scp) || sc->fbi == NULL)
3093 sc_set_border(scp, scp->border);
984263bc
MD
3094
3095 /* set up the keyboard for the new screen */
3096 if (sc->old_scp->kbd_mode != scp->kbd_mode)
3097 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
f6ce8b19 3098 update_kbd_state(scp, scp->status, LOCK_MASK, TRUE);
984263bc
MD
3099
3100 mark_all(scp);
ba409a88
IV
3101
3102 /*
3103 * Restore DRM framebuffer console mode if necessary.
3104 * Especially avoid modesetting when switching to a vt which is in
3105 * graphics mode, because the fb_set_par() from the taskqueue thread
3106 * might race with the modesetting ioctl from the userland application.
3107 */
0d7c8a4d 3108 if (!ISTEXTSC(sc->old_scp) &&
ba409a88
IV
3109 sc->fbi != NULL && sc->fbi->fbops.fb_set_par != NULL &&
3110 sc->fb_set_par_task != NULL) {
3111 taskqueue_enqueue(taskqueue_thread[0], sc->fb_set_par_task);
3112 }
3113
2efb75f3 3114 lwkt_reltoken(&vga_token);
984263bc
MD
3115}
3116
82d1ed25 3117static void
984263bc
MD
3118sc_puts(scr_stat *scp, u_char *buf, int len)
3119{
3120#if NSPLASH > 0
3121 /* make screensaver happy */
3122 if (!sticky_splash && scp == scp->sc->cur_scp)
3123 run_scrn_saver = FALSE;
3124#endif
3125
3126 if (scp->tsw)
3127 (*scp->tsw->te_puts)(scp, buf, len);
3128
3129 if (scp->sc->delayed_next_scr)
3130 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
22ff886e 3131
984263bc
MD
3132}
3133
3134void
3135sc_draw_cursor_image(scr_stat *scp)
3136{
3137 /* assert(scp == scp->sc->cur_scp); */
7ae6dbf0 3138 atomic_add_int(&scp->sc->videoio_in_progress, 1);
984263bc
MD
3139 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
3140 scp->sc->flags & SC_BLINK_CURSOR, TRUE,
3141 sc_inside_cutmark(scp, scp->cursor_pos));
3142 scp->cursor_oldpos = scp->cursor_pos;
7ae6dbf0 3143 atomic_add_int(&scp->sc->videoio_in_progress, -1);
984263bc
MD
3144}
3145
3146void
3147sc_remove_cursor_image(scr_stat *scp)
3148{
3149 /* assert(scp == scp->sc->cur_scp); */
7ae6dbf0 3150 atomic_add_int(&scp->sc->videoio_in_progress, 1);
984263bc
MD
3151 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
3152 scp->sc->flags & SC_BLINK_CURSOR, FALSE,
3153 sc_inside_cutmark(scp, scp->cursor_oldpos));
7ae6dbf0 3154 atomic_add_int(&scp->sc->videoio_in_progress, -1);
984263bc
MD
3155}
3156
3157static void
3158update_cursor_image(scr_stat *scp)
3159{
3160 int blink;
3161
3162 if (scp->sc->flags & SC_CHAR_CURSOR) {
3163 scp->cursor_base = imax(0, scp->sc->cursor_base);
219917ca 3164 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_height);
984263bc
MD
3165 } else {
3166 scp->cursor_base = 0;
219917ca 3167 scp->cursor_height = scp->font_height;
984263bc
MD
3168 }
3169 blink = scp->sc->flags & SC_BLINK_CURSOR;
3170
3171 /* assert(scp == scp->sc->cur_scp); */
7ae6dbf0 3172 atomic_add_int(&scp->sc->videoio_in_progress, 1);
984263bc
MD
3173 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
3174 sc_inside_cutmark(scp, scp->cursor_pos));
3175 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
3176 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
3177 sc_inside_cutmark(scp, scp->cursor_pos));
7ae6dbf0 3178 atomic_add_int(&scp->sc->videoio_in_progress, -1);
984263bc
MD
3179}
3180
3181void
3182sc_set_cursor_image(scr_stat *scp)
3183{
3184 if (scp->sc->flags & SC_CHAR_CURSOR) {
3185 scp->cursor_base = imax(0, scp->sc->cursor_base);
219917ca 3186 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_height);
984263bc
MD
3187 } else {
3188 scp->cursor_base = 0;
219917ca 3189 scp->cursor_height = scp->font_height;
984263bc
MD
3190 }
3191
3192 /* assert(scp == scp->sc->cur_scp); */