kernel/syscons: Add simple font scaling when using KMS drivers.
[dragonfly.git] / sys / dev / misc / syscons / syscons.c
blob12341ef432a8f6c29c37d18077e24979e39655d6
1 /*-
2 * Copyright (c) 1992-1998 Søren Schmidt
3 * All rights reserved.
5 * This code is derived from software contributed to The DragonFly Project
6 * by Sascha Wildner <saw@online.de>
8 * Simple font scaling code by Sascha Wildner and Matthew Dillon
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.
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.
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 $
36 #include "use_splash.h"
37 #include "opt_syscons.h"
38 #include "opt_ddb.h"
39 #ifdef __i386__
40 #include "use_apm.h"
41 #endif
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/eventhandler.h>
46 #include <sys/reboot.h>
47 #include <sys/conf.h>
48 #include <sys/proc.h>
49 #include <sys/priv.h>
50 #include <sys/signalvar.h>
51 #include <sys/sysctl.h>
52 #include <sys/tty.h>
53 #include <sys/kernel.h>
54 #include <sys/cons.h>
55 #include <sys/random.h>
57 #include <sys/thread2.h>
58 #include <sys/mutex2.h>
60 #include <machine/clock.h>
61 #include <machine/console.h>
62 #include <machine/psl.h>
63 #include <machine/pc/display.h>
64 #ifdef __i386__
65 #include <machine/apm_bios.h>
66 #endif
67 #include <machine/frame.h>
69 #include <dev/drm/include/linux/fb.h>
70 #include <dev/misc/kbd/kbdreg.h>
71 #include <dev/video/fb/fbreg.h>
72 #include <dev/video/fb/splashreg.h>
73 #include "syscons.h"
75 #define COLD 0
76 #define WARM 1
78 #define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
79 #define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
81 #define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */
82 #define WANT_UNLOCK(m) do { \
83 if (m) \
84 syscons_unlock(); \
85 } while (0)
87 #define WANT_LOCK(m) do { \
88 if (m) \
89 syscons_lock(); \
90 } while(0)
93 MALLOC_DEFINE(M_SYSCONS, "syscons", "Syscons");
95 typedef struct default_attr {
96 int std_color; /* normal hardware color */
97 int rev_color; /* reverse hardware color */
98 } default_attr;
100 static default_attr user_default = {
101 SC_NORM_ATTR,
102 SC_NORM_REV_ATTR,
105 static default_attr kernel_default = {
106 SC_KERNEL_CONS_ATTR,
107 SC_KERNEL_CONS_REV_ATTR,
110 static int sc_console_unit = -1;
111 static scr_stat *sc_console;
112 static struct tty *sc_console_tty;
113 static void *kernel_console_ts;
115 static char init_done = COLD;
116 static char shutdown_in_progress = FALSE;
117 static char sc_malloc = FALSE;
119 static int saver_mode = CONS_NO_SAVER; /* LKM/user saver */
120 static int run_scrn_saver = FALSE; /* should run the saver? */
121 static long scrn_blank_time = 0; /* screen saver timeout value */
122 #if NSPLASH > 0
123 static int scrn_blanked; /* # of blanked screen */
124 static int sticky_splash = FALSE;
126 static void none_saver(sc_softc_t *sc, int blank) { }
127 static void (*current_saver)(sc_softc_t *, int) = none_saver;
128 #endif
130 #if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
131 #include "font.h"
132 #endif
134 static bios_values_t bios_value;
136 static int enable_panic_key;
137 SYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key,
138 0, "Enable the panic key (CTRL-ALT-SHIFT-ESC)");
140 #define SC_CONSOLECTL 255
142 #define VIRTUAL_TTY(sc, x) ((SC_DEV((sc),(x)) != NULL) ? \
143 (SC_DEV((sc),(x))->si_tty) : NULL)
144 #define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
146 static int debugger;
147 static cdev_t cctl_dev;
148 #if 0
149 static timeout_t blink_screen_callout;
150 #endif
151 static void sc_blink_screen(scr_stat *scp);
152 static struct mtx syscons_mtx = MTX_INITIALIZER("syscons");
154 /* prototypes */
155 static int scvidprobe(int unit, int flags, int cons);
156 static int sckbdprobe(int unit, int flags, int cons);
157 static void scmeminit(void *arg);
158 static int scdevtounit(cdev_t dev);
159 static kbd_callback_func_t sckbdevent;
160 static int scparam(struct tty *tp, struct termios *t);
161 static void scstart(struct tty *tp);
162 static void scinit(int unit, int flags);
163 static void scterm(int unit, int flags);
164 static void scshutdown(void *arg, int howto);
165 static void sc_puts(scr_stat *scp, u_char *buf, int len);
166 static u_int scgetc(sc_softc_t *sc, u_int flags);
167 #define SCGETC_CN 1
168 #define SCGETC_NONBLOCK 2
169 static int sccngetch(int flags);
170 static void sccnupdate(scr_stat *scp);
171 static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
172 static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
173 static timeout_t scrn_timer;
174 static int and_region(int *s1, int *e1, int s2, int e2);
175 static void scrn_update(scr_stat *scp, int show_cursor);
177 #if NSPLASH > 0
178 static int scsplash_callback(int event, void *arg);
179 static void scsplash_saver(sc_softc_t *sc, int show);
180 static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
181 static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
182 static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
183 static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
184 static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
185 static int wait_scrn_saver_stop(sc_softc_t *sc);
186 #define scsplash_stick(stick) (sticky_splash = (stick))
187 #else /* !NSPLASH */
188 #define scsplash_stick(stick)
189 #endif /* NSPLASH */
191 static void do_switch_scr(sc_softc_t *sc);
192 static int vt_proc_alive(scr_stat *scp);
193 static int signal_vt_rel(scr_stat *scp);
194 static int signal_vt_acq(scr_stat *scp);
195 static int finish_vt_rel(scr_stat *scp, int release);
196 static int finish_vt_acq(scr_stat *scp);
197 static void exchange_scr(sc_softc_t *sc);
198 static void update_cursor_image(scr_stat *scp);
199 static int save_kbd_state(scr_stat *scp, int unlock);
200 static int update_kbd_state(scr_stat *scp, int state, int mask, int unlock);
201 static int update_kbd_leds(scr_stat *scp, int which);
202 static int sc_allocate_keyboard(sc_softc_t *sc, int unit);
205 * Console locking support functions.
207 * We use mutex spinlocks here in order to allow reentrancy which should
208 * avoid issues during panics.
210 static void
211 syscons_lock(void)
213 mtx_spinlock(&syscons_mtx);
217 * Returns 0 on success, EAGAIN on failure.
219 static int
220 syscons_lock_nonblock(void)
222 return(mtx_spinlock_try(&syscons_mtx));
225 static void
226 syscons_unlock(void)
228 mtx_spinunlock(&syscons_mtx);
232 * Console driver
234 static cn_probe_t sccnprobe;
235 static cn_init_t sccninit;
236 static cn_init_t sccninit_fini;
237 static cn_getc_t sccngetc;
238 static cn_checkc_t sccncheckc;
239 static cn_putc_t sccnputc;
240 static cn_dbctl_t sccndbctl;
241 static cn_term_t sccnterm;
243 CONS_DRIVER(sc, sccnprobe, sccninit, sccninit_fini, sccnterm,
244 sccngetc, sccncheckc, sccnputc, sccndbctl);
246 static d_open_t scopen;
247 static d_close_t scclose;
248 static d_read_t scread;
249 static d_ioctl_t scioctl;
250 static d_mmap_t scmmap;
252 static struct dev_ops sc_ops = {
253 { "sc", 0, D_TTY },
254 .d_open = scopen,
255 .d_close = scclose,
256 .d_read = scread,
257 .d_write = ttywrite,
258 .d_ioctl = scioctl,
259 .d_mmap = scmmap,
260 .d_kqfilter = ttykqfilter,
261 .d_revoke = ttyrevoke
265 sc_probe_unit(int unit, int flags)
267 if (!scvidprobe(unit, flags, FALSE)) {
268 if (bootverbose)
269 kprintf("sc%d: no video adapter found.\n", unit);
270 return ENXIO;
273 /* syscons will be attached even when there is no keyboard */
274 sckbdprobe(unit, flags, FALSE);
276 return 0;
280 register_framebuffer(struct fb_info *info)
282 sc_softc_t *sc;
284 /* For now ignore framebuffers, which don't replace the vga display */
285 if (!info->is_vga_boot_display)
286 return 0;
288 lwkt_gettoken(&tty_token);
289 sc = sc_get_softc(0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
290 if (sc == NULL) {
291 lwkt_reltoken(&tty_token);
292 kprintf("%s: sc_get_softc(%d, %d) returned NULL\n", __func__,
293 0, (sc_console_unit == 0) ? SC_KERNEL_CONSOLE : 0);
294 return 0;
297 /* Ignore this framebuffer if we have already switched to a framebuffer */
298 if (sc->fbi != NULL) {
299 lwkt_reltoken(&tty_token);
300 return 0;
303 sc->fbi = info;
305 if (sc->fbi != NULL) {
306 sc_update_render(sc->cur_scp);
307 sc->fbi->restore(sc->fbi->cookie);
310 lwkt_reltoken(&tty_token);
311 return 0;
314 /* probe video adapters, return TRUE if found */
315 static int
316 scvidprobe(int unit, int flags, int cons)
319 * Access the video adapter driver through the back door!
320 * Video adapter drivers need to be configured before syscons.
321 * However, when syscons is being probed as the low-level console,
322 * they have not been initialized yet. We force them to initialize
323 * themselves here. XXX
325 vid_configure(cons ? VIO_PROBE_ONLY : 0);
327 return (vid_find_adapter("*", unit) >= 0);
330 /* probe the keyboard, return TRUE if found */
331 static int
332 sckbdprobe(int unit, int flags, int cons)
334 /* access the keyboard driver through the backdoor! */
335 kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
337 return (kbd_find_keyboard("*", unit) >= 0);
340 static char *
341 adapter_name(video_adapter_t *adp)
343 static struct {
344 int type;
345 char *name[2];
346 } names[] = {
347 { KD_MONO, { "MDA", "MDA" } },
348 { KD_HERCULES, { "Hercules", "Hercules" } },
349 { KD_CGA, { "CGA", "CGA" } },
350 { KD_EGA, { "EGA", "EGA (mono)" } },
351 { KD_VGA, { "VGA", "VGA (mono)" } },
352 { KD_TGA, { "TGA", "TGA" } },
353 { -1, { "Unknown", "Unknown" } },
355 int i;
357 for (i = 0; names[i].type != -1; ++i)
358 if (names[i].type == adp->va_type)
359 break;
360 return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
364 sc_attach_unit(int unit, int flags)
366 sc_softc_t *sc;
367 scr_stat *scp;
368 #ifdef SC_PIXEL_MODE
369 video_info_t info;
370 #endif
371 int vc;
372 cdev_t dev;
373 flags &= ~SC_KERNEL_CONSOLE;
375 if (sc_console_unit == unit) {
377 * If this unit is being used as the system console, we need to
378 * adjust some variables and buffers before and after scinit().
380 /* assert(sc_console != NULL) */
381 flags |= SC_KERNEL_CONSOLE;
382 scmeminit(NULL);
384 scinit(unit, flags);
386 if (sc_console->tsw->te_size > 0) {
387 /* assert(sc_console->ts != NULL); */
388 kernel_console_ts = sc_console->ts;
389 sc_console->ts = kmalloc(sc_console->tsw->te_size,
390 M_SYSCONS, M_WAITOK);
391 bcopy(kernel_console_ts, sc_console->ts, sc_console->tsw->te_size);
392 (*sc_console->tsw->te_default_attr)(sc_console,
393 user_default.std_color,
394 user_default.rev_color);
396 } else {
397 scinit(unit, flags);
400 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
403 * If this is the console we couldn't setup sc->dev before because
404 * malloc wasn't working. Set it up now.
406 if (flags & SC_KERNEL_CONSOLE) {
407 KKASSERT(sc->dev == NULL);
408 sc->dev = kmalloc(sizeof(cdev_t)*sc->vtys, M_SYSCONS, M_WAITOK|M_ZERO);
409 sc->dev[0] = make_dev(&sc_ops, sc_console_unit*MAXCONS, UID_ROOT,
410 GID_WHEEL, 0600,
411 "ttyv%r", sc_console_unit*MAXCONS);
412 sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
413 sc->dev[0]->si_drv1 = sc_console;
417 * Finish up the standard attach
419 sc->config = flags;
420 callout_init_mp(&sc->scrn_timer_ch);
421 scp = SC_STAT(sc->dev[0]);
422 if (sc_console == NULL) /* sc_console_unit < 0 */
423 sc_console = scp;
425 #ifdef SC_PIXEL_MODE
426 if ((sc->config & SC_VESA800X600)
427 && ((*vidsw[sc->adapter]->get_info)(sc->adp, M_VESA_800x600, &info) == 0)) {
428 #if NSPLASH > 0
429 if (sc->flags & SC_SPLASH_SCRN)
430 splash_term(sc->adp);
431 #endif
432 sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
433 sc_set_pixel_mode(scp, NULL, 0, 0, 16);
434 sc->initial_mode = M_VESA_800x600;
435 #if NSPLASH > 0
436 /* put up the splash again! */
437 if (sc->flags & SC_SPLASH_SCRN)
438 splash_init(sc->adp, scsplash_callback, sc);
439 #endif
441 #endif /* SC_PIXEL_MODE */
443 /* initialize cursor */
444 if (!ISGRAPHSC(scp))
445 update_cursor_image(scp);
447 /* get screen update going */
448 scrn_timer(sc);
450 /* set up the keyboard */
451 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
452 update_kbd_state(scp, scp->status, LOCK_MASK, FALSE);
454 kprintf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
455 unit, adapter_name(sc->adp), sc->vtys, sc->config);
456 if (bootverbose) {
457 kprintf("sc%d:", unit);
458 if (sc->adapter >= 0)
459 kprintf(" fb%d", sc->adapter);
460 if (sc->keyboard >= 0)
461 kprintf(", kbd%d", sc->keyboard);
462 if (scp->tsw)
463 kprintf(", terminal emulator: %s (%s)",
464 scp->tsw->te_name, scp->tsw->te_desc);
465 kprintf("\n");
468 /* register a shutdown callback for the kernel console */
469 if (sc_console_unit == unit)
470 EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown,
471 (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
474 * create devices.
476 * The first vty already has struct tty and scr_stat initialized
477 * in scinit(). The other vtys will have these structs when
478 * first opened.
480 for (vc = 1; vc < sc->vtys; vc++) {
481 dev = make_dev(&sc_ops, vc + unit * MAXCONS,
482 UID_ROOT, GID_WHEEL,
483 0600, "ttyv%r", vc + unit * MAXCONS);
484 sc->dev[vc] = dev;
486 cctl_dev = make_dev(&sc_ops, SC_CONSOLECTL,
487 UID_ROOT, GID_WHEEL, 0600, "consolectl");
488 cctl_dev->si_tty = sc_console_tty = ttymalloc(sc_console_tty);
489 cctl_dev->si_drv1 = sc_console;
490 return 0;
493 static void
494 scmeminit(void *arg)
496 if (sc_malloc)
497 return;
498 sc_malloc = TRUE;
501 * As soon as malloc() becomes functional, we had better allocate
502 * various buffers for the kernel console.
505 if (sc_console_unit < 0) /* sc_console == NULL */
506 return;
508 /* copy the temporary buffer to the final buffer */
509 sc_alloc_scr_buffer(sc_console, TRUE, FALSE);
511 #ifndef SC_NO_CUTPASTE
512 sc_alloc_cut_buffer(sc_console, TRUE);
513 #endif
515 #ifndef SC_NO_HISTORY
516 /* initialize history buffer & pointers */
517 sc_alloc_history_buffer(sc_console, 0, 0, TRUE);
518 #endif
521 SYSINIT(sc_mem, SI_BOOT1_POST, SI_ORDER_ANY, scmeminit, NULL);
523 static int
524 scdevtounit(cdev_t dev)
526 int vty = SC_VTY(dev);
528 if (vty == SC_CONSOLECTL)
529 return ((sc_console != NULL) ? sc_console->sc->unit : -1);
530 else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
531 return -1;
532 else
533 return vty/MAXCONS;
537 scopen(struct dev_open_args *ap)
539 cdev_t dev = ap->a_head.a_dev;
540 int unit;
541 sc_softc_t *sc;
542 struct tty *tp;
543 scr_stat *scp;
544 keyarg_t key;
545 int error;
547 lwkt_gettoken(&tty_token);
548 unit = scdevtounit(dev);
549 DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
550 major(dev), minor(dev), unit, SC_VTY(dev)));
552 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
553 if (sc == NULL) {
554 lwkt_reltoken(&tty_token);
555 return ENXIO;
558 tp = dev->si_tty = ttymalloc(dev->si_tty);
559 tp->t_oproc = scstart;
560 tp->t_param = scparam;
561 tp->t_stop = nottystop;
563 tp->t_dev = dev;
565 if (!ISTTYOPEN(tp)) {
566 ttychars(tp);
567 /* Use the current setting of the <-- key as default VERASE. */
568 /* If the Delete key is preferable, an stty is necessary */
569 if (sc->kbd != NULL) {
570 key.keynum = KEYCODE_BS;
571 kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
572 tp->t_cc[VERASE] = key.key.map[0];
574 tp->t_iflag = TTYDEF_IFLAG;
575 tp->t_oflag = TTYDEF_OFLAG;
576 tp->t_cflag = TTYDEF_CFLAG;
577 tp->t_lflag = TTYDEF_LFLAG;
578 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
579 scparam(tp, &tp->t_termios);
580 (*linesw[tp->t_line].l_modem)(tp, 1);
582 else
583 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
584 lwkt_reltoken(&tty_token);
585 return(EBUSY);
588 error = (*linesw[tp->t_line].l_open)(dev, tp);
590 scp = SC_STAT(dev);
591 if (scp == NULL) {
592 scp = dev->si_drv1 = alloc_scp(sc, SC_VTY(dev));
593 syscons_lock();
594 if (ISGRAPHSC(scp))
595 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
596 syscons_unlock();
598 if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
599 tp->t_winsize.ws_col = scp->xsize;
600 tp->t_winsize.ws_row = scp->ysize;
603 lwkt_reltoken(&tty_token);
604 return error;
608 scclose(struct dev_close_args *ap)
610 cdev_t dev = ap->a_head.a_dev;
611 struct tty *tp = dev->si_tty;
612 scr_stat *scp;
614 lwkt_gettoken(&tty_token);
615 if (SC_VTY(dev) != SC_CONSOLECTL) {
616 scp = SC_STAT(tp->t_dev);
617 /* were we in the middle of the VT switching process? */
618 DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
619 if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit))
620 cons_unavail = FALSE;
621 if (finish_vt_rel(scp, TRUE) == 0) /* force release */
622 DPRINTF(5, ("reset WAIT_REL, "));
623 if (finish_vt_acq(scp) == 0) /* force acknowledge */
624 DPRINTF(5, ("reset WAIT_ACQ, "));
625 syscons_lock();
626 #if 0 /* notyet */
627 if (scp == &main_console) {
628 scp->pid = 0;
629 scp->proc = NULL;
630 scp->smode.mode = VT_AUTO;
632 else {
633 sc_vtb_destroy(&scp->vtb);
634 sc_vtb_destroy(&scp->scr);
635 sc_free_history_buffer(scp, scp->ysize);
636 SC_STAT(dev) = NULL;
637 kfree(scp, M_SYSCONS);
639 #else
640 scp->pid = 0;
641 scp->proc = NULL;
642 scp->smode.mode = VT_AUTO;
643 #endif
644 scp->kbd_mode = K_XLATE;
645 syscons_unlock();
646 if (scp == scp->sc->cur_scp)
647 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
648 DPRINTF(5, ("done.\n"));
650 (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
651 ttyclose(tp);
652 lwkt_reltoken(&tty_token);
654 return(0);
658 scread(struct dev_read_args *ap)
660 int ret;
662 lwkt_gettoken(&tty_token);
663 sc_touch_scrn_saver();
664 ret = ttyread(ap);
665 lwkt_reltoken(&tty_token);
666 return ret;
669 static int
670 sckbdevent(keyboard_t *thiskbd, int event, void *arg)
672 sc_softc_t *sc;
673 struct tty *cur_tty;
674 int c;
675 size_t len;
676 u_char *cp;
678 lwkt_gettoken(&tty_token);
680 * WARNING: In early boot sc->dev may not be setup yet.
682 sc = (sc_softc_t *)arg;
683 /* assert(thiskbd == sc->kbd) */
685 switch (event) {
686 case KBDIO_KEYINPUT:
687 break;
688 case KBDIO_UNLOADING:
689 syscons_lock();
690 sc->kbd = NULL;
691 sc->keyboard = -1;
692 syscons_unlock();
693 kbd_release(thiskbd, (void *)&sc->keyboard);
694 lwkt_reltoken(&tty_token);
695 return 0;
696 default:
697 lwkt_reltoken(&tty_token);
698 return EINVAL;
702 * Loop while there is still input to get from the keyboard.
703 * I don't think this is nessesary, and it doesn't fix
704 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
706 while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
707 cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
708 if (!ISTTYOPEN(cur_tty)) {
709 cur_tty = sc_console_tty;
710 if (!ISTTYOPEN(cur_tty))
711 continue;
714 syscons_lock();
715 if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty)) {
716 syscons_unlock();
717 continue;
719 syscons_unlock();
721 switch (KEYFLAGS(c)) {
722 case 0x0000: /* normal key */
723 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
724 break;
725 case FKEY: /* function key, return string */
726 cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
727 if (cp != NULL) {
728 while (len-- > 0)
729 (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
731 break;
732 case MKEY: /* meta is active, prepend ESC */
733 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
734 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
735 break;
736 case BKEY: /* backtab fixed sequence (esc [ Z) */
737 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
738 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
739 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
740 break;
744 syscons_lock();
745 sc->cur_scp->status |= MOUSE_HIDDEN;
746 syscons_unlock();
748 lwkt_reltoken(&tty_token);
749 return 0;
752 static int
753 scparam(struct tty *tp, struct termios *t)
755 lwkt_gettoken(&tty_token);
756 tp->t_ispeed = t->c_ispeed;
757 tp->t_ospeed = t->c_ospeed;
758 tp->t_cflag = t->c_cflag;
759 lwkt_reltoken(&tty_token);
760 return 0;
764 scioctl(struct dev_ioctl_args *ap)
766 cdev_t dev = ap->a_head.a_dev;
767 u_long cmd = ap->a_cmd;
768 caddr_t data = ap->a_data;
769 int flag = ap->a_fflag;
770 int error;
771 int i;
772 struct tty *tp;
773 sc_softc_t *sc;
774 scr_stat *scp;
776 lwkt_gettoken(&tty_token);
777 tp = dev->si_tty;
779 error = sc_vid_ioctl(tp, cmd, data, flag);
780 if (error != ENOIOCTL) {
781 lwkt_reltoken(&tty_token);
782 return error;
785 #ifndef SC_NO_HISTORY
786 error = sc_hist_ioctl(tp, cmd, data, flag);
787 if (error != ENOIOCTL) {
788 lwkt_reltoken(&tty_token);
789 return error;
791 #endif
793 #ifndef SC_NO_SYSMOUSE
794 error = sc_mouse_ioctl(tp, cmd, data, flag);
795 if (error != ENOIOCTL) {
796 lwkt_reltoken(&tty_token);
797 return error;
799 #endif
801 scp = SC_STAT(tp->t_dev);
802 /* assert(scp != NULL) */
803 /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
804 sc = scp->sc;
806 if (scp->tsw) {
807 syscons_lock();
808 error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, flag);
809 syscons_unlock();
810 if (error != ENOIOCTL) {
811 lwkt_reltoken(&tty_token);
812 return error;
816 switch (cmd) { /* process console hardware related ioctl's */
818 case GIO_ATTR: /* get current attributes */
819 /* this ioctl is not processed here, but in the terminal emulator */
820 lwkt_reltoken(&tty_token);
821 return ENOTTY;
823 case GIO_COLOR: /* is this a color console ? */
824 *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
825 lwkt_reltoken(&tty_token);
826 return 0;
828 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
829 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME) {
830 lwkt_reltoken(&tty_token);
831 return EINVAL;
833 syscons_lock();
834 scrn_blank_time = *(int *)data;
835 run_scrn_saver = (scrn_blank_time != 0);
836 syscons_unlock();
837 lwkt_reltoken(&tty_token);
838 return 0;
840 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
841 syscons_lock();
842 if (!ISGRAPHSC(sc->cur_scp))
843 sc_remove_cursor_image(sc->cur_scp);
844 if ((*(int*)data) & 0x01)
845 sc->flags |= SC_BLINK_CURSOR;
846 else
847 sc->flags &= ~SC_BLINK_CURSOR;
848 if ((*(int*)data) & 0x02) {
849 sc->flags |= SC_CHAR_CURSOR;
850 } else
851 sc->flags &= ~SC_CHAR_CURSOR;
853 * The cursor shape is global property; all virtual consoles
854 * are affected. Update the cursor in the current console...
856 if (!ISGRAPHSC(sc->cur_scp)) {
857 sc_set_cursor_image(sc->cur_scp);
858 sc_draw_cursor_image(sc->cur_scp);
860 syscons_unlock();
861 lwkt_reltoken(&tty_token);
862 return 0;
864 case CONS_BELLTYPE: /* set bell type sound/visual */
865 syscons_lock();
867 if ((*(int *)data) & 0x01)
868 sc->flags |= SC_VISUAL_BELL;
869 else
870 sc->flags &= ~SC_VISUAL_BELL;
872 if ((*(int *)data) & 0x02)
873 sc->flags |= SC_QUIET_BELL;
874 else
875 sc->flags &= ~SC_QUIET_BELL;
877 syscons_unlock();
878 lwkt_reltoken(&tty_token);
879 return 0;
881 case CONS_GETINFO: /* get current (virtual) console info */
883 vid_info_t *ptr = (vid_info_t*)data;
884 if (ptr->size == sizeof(struct vid_info)) {
885 ptr->m_num = sc->cur_scp->index;
886 ptr->font_size = scp->font_height;
887 ptr->mv_col = scp->xpos;
888 ptr->mv_row = scp->ypos;
889 ptr->mv_csz = scp->xsize;
890 ptr->mv_rsz = scp->ysize;
892 * The following fields are filled by the terminal emulator. XXX
894 * ptr->mv_norm.fore
895 * ptr->mv_norm.back
896 * ptr->mv_rev.fore
897 * ptr->mv_rev.back
899 ptr->mv_grfc.fore = 0; /* not supported */
900 ptr->mv_grfc.back = 0; /* not supported */
901 ptr->mv_ovscan = scp->border;
902 if (scp == sc->cur_scp)
903 save_kbd_state(scp, FALSE);
904 ptr->mk_keylock = scp->status & LOCK_MASK;
905 lwkt_reltoken(&tty_token);
906 return 0;
908 lwkt_reltoken(&tty_token);
909 return EINVAL;
912 case CONS_GETVERS: /* get version number */
913 *(int*)data = 0x200; /* version 2.0 */
914 lwkt_reltoken(&tty_token);
915 return 0;
917 case CONS_IDLE: /* see if the screen has been idle */
919 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
920 * the user process may have been writing something on the
921 * screen and syscons is not aware of it. Declare the screen
922 * is NOT idle if it is in one of these modes. But there is
923 * an exception to it; if a screen saver is running in the
924 * graphics mode in the current screen, we should say that the
925 * screen has been idle.
927 *(int *)data = (sc->flags & SC_SCRN_IDLE)
928 && (!ISGRAPHSC(sc->cur_scp)
929 || (sc->cur_scp->status & SAVER_RUNNING));
930 lwkt_reltoken(&tty_token);
931 return 0;
933 case CONS_SAVERMODE: /* set saver mode */
934 switch(*(int *)data) {
935 case CONS_NO_SAVER:
936 case CONS_USR_SAVER:
937 syscons_lock();
938 /* if a LKM screen saver is running, stop it first. */
939 scsplash_stick(FALSE);
940 saver_mode = *(int *)data;
941 #if NSPLASH > 0
942 if ((error = wait_scrn_saver_stop(NULL))) {
943 syscons_unlock();
944 lwkt_reltoken(&tty_token);
945 return error;
947 #endif /* NSPLASH */
948 run_scrn_saver = TRUE;
949 if (saver_mode == CONS_USR_SAVER)
950 scp->status |= SAVER_RUNNING;
951 else
952 scp->status &= ~SAVER_RUNNING;
953 scsplash_stick(TRUE);
954 syscons_unlock();
955 break;
956 case CONS_LKM_SAVER:
957 syscons_lock();
958 if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
959 scp->status &= ~SAVER_RUNNING;
960 saver_mode = *(int *)data;
961 syscons_unlock();
962 break;
963 default:
964 lwkt_reltoken(&tty_token);
965 return EINVAL;
967 lwkt_reltoken(&tty_token);
968 return 0;
970 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
972 * Note that this ioctl does not guarantee the screen saver
973 * actually starts or stops. It merely attempts to do so...
975 syscons_lock();
976 run_scrn_saver = (*(int *)data != 0);
977 if (run_scrn_saver)
978 sc->scrn_time_stamp -= scrn_blank_time;
979 syscons_unlock();
980 lwkt_reltoken(&tty_token);
981 return 0;
983 case CONS_SCRSHOT: /* get a screen shot */
985 scrshot_t *ptr = (scrshot_t*)data;
986 syscons_lock();
987 if (ISGRAPHSC(scp)) {
988 syscons_unlock();
989 lwkt_reltoken(&tty_token);
990 return EOPNOTSUPP;
992 if (scp->xsize != ptr->xsize || scp->ysize != ptr->ysize) {
993 syscons_unlock();
994 lwkt_reltoken(&tty_token);
995 return EINVAL;
997 syscons_unlock();
998 copyout ((void*)scp->vtb.vtb_buffer, ptr->buf,
999 ptr->xsize * ptr->ysize * sizeof(uint16_t));
1000 lwkt_reltoken(&tty_token);
1001 return 0;
1004 case VT_SETMODE: /* set screen switcher mode */
1006 struct vt_mode *mode;
1008 mode = (struct vt_mode *)data;
1009 DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
1010 if (scp->smode.mode == VT_PROCESS) {
1011 if (scp->proc == pfindn(scp->pid) && scp->proc != curproc) {
1012 DPRINTF(5, ("error EPERM\n"));
1013 lwkt_reltoken(&tty_token);
1014 return EPERM;
1017 syscons_lock();
1018 if (mode->mode == VT_AUTO) {
1019 scp->smode.mode = VT_AUTO;
1020 scp->proc = NULL;
1021 scp->pid = 0;
1022 DPRINTF(5, ("VT_AUTO, "));
1023 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
1024 cons_unavail = FALSE;
1025 if (finish_vt_rel(scp, TRUE) == 0)
1026 DPRINTF(5, ("reset WAIT_REL, "));
1027 if (finish_vt_acq(scp) == 0)
1028 DPRINTF(5, ("reset WAIT_ACQ, "));
1029 } else {
1030 if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
1031 || !ISSIGVALID(mode->frsig)) {
1032 syscons_unlock();
1033 DPRINTF(5, ("error EINVAL\n"));
1034 lwkt_reltoken(&tty_token);
1035 return EINVAL;
1037 DPRINTF(5, ("VT_PROCESS %d, ", curproc->p_pid));
1038 bcopy(data, &scp->smode, sizeof(struct vt_mode));
1039 scp->proc = curproc;
1040 scp->pid = scp->proc->p_pid;
1041 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
1042 cons_unavail = TRUE;
1044 syscons_unlock();
1045 DPRINTF(5, ("\n"));
1046 lwkt_reltoken(&tty_token);
1047 return 0;
1050 case VT_GETMODE: /* get screen switcher mode */
1051 bcopy(&scp->smode, data, sizeof(struct vt_mode));
1052 lwkt_reltoken(&tty_token);
1053 return 0;
1055 case VT_RELDISP: /* screen switcher ioctl */
1057 * This must be the current vty which is in the VT_PROCESS
1058 * switching mode...
1060 syscons_lock();
1061 if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
1062 syscons_unlock();
1063 lwkt_reltoken(&tty_token);
1064 return EINVAL;
1066 /* ...and this process is controlling it. */
1067 if (scp->proc != curproc) {
1068 syscons_unlock();
1069 lwkt_reltoken(&tty_token);
1070 return EPERM;
1072 error = EINVAL;
1073 switch(*(int *)data) {
1074 case VT_FALSE: /* user refuses to release screen, abort */
1075 if ((error = finish_vt_rel(scp, FALSE)) == 0)
1076 DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
1077 break;
1078 case VT_TRUE: /* user has released screen, go on */
1079 if ((error = finish_vt_rel(scp, TRUE)) == 0)
1080 DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
1081 break;
1082 case VT_ACKACQ: /* acquire acknowledged, switch completed */
1083 if ((error = finish_vt_acq(scp)) == 0)
1084 DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
1085 break;
1086 default:
1087 break;
1089 syscons_unlock();
1090 lwkt_reltoken(&tty_token);
1091 return error;
1093 case VT_OPENQRY: /* return free virtual console */
1094 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
1095 tp = VIRTUAL_TTY(sc, i);
1096 if (!ISTTYOPEN(tp)) {
1097 *(int *)data = i + 1;
1098 lwkt_reltoken(&tty_token);
1099 return 0;
1102 lwkt_reltoken(&tty_token);
1103 return EINVAL;
1105 case VT_ACTIVATE: /* switch to screen *data */
1106 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
1107 syscons_lock();
1108 sc_clean_up(sc->cur_scp);
1109 error = sc_switch_scr(sc, i);
1110 syscons_unlock();
1111 lwkt_reltoken(&tty_token);
1112 return error;
1114 case VT_WAITACTIVE: /* wait for switch to occur */
1115 i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
1116 if ((i < sc->first_vty) || (i >= sc->first_vty + sc->vtys)) {
1117 lwkt_reltoken(&tty_token);
1118 return EINVAL;
1120 syscons_lock();
1121 error = sc_clean_up(sc->cur_scp);
1122 syscons_unlock();
1123 if (error) {
1124 lwkt_reltoken(&tty_token);
1125 return error;
1129 * scp might be NULL, we aren't sure why. Check for NULL.
1131 * http://bugs.dragonflybsd.org/issues/2481
1133 scp = SC_STAT(SC_DEV(sc, i));
1134 if (scp == NULL || scp == scp->sc->cur_scp) {
1135 lwkt_reltoken(&tty_token);
1136 return 0;
1138 error = tsleep((caddr_t)&scp->smode, PCATCH, "waitvt", 0);
1139 /* May return ERESTART */
1140 lwkt_reltoken(&tty_token);
1141 return error;
1143 case VT_GETACTIVE: /* get active vty # */
1144 *(int *)data = sc->cur_scp->index + 1;
1145 lwkt_reltoken(&tty_token);
1146 return 0;
1148 case VT_GETINDEX: /* get this vty # */
1149 *(int *)data = scp->index + 1;
1150 lwkt_reltoken(&tty_token);
1151 return 0;
1153 case VT_LOCKSWITCH: /* prevent vty switching */
1154 syscons_lock();
1155 if ((*(int *)data) & 0x01)
1156 sc->flags |= SC_SCRN_VTYLOCK;
1157 else
1158 sc->flags &= ~SC_SCRN_VTYLOCK;
1159 syscons_unlock();
1160 lwkt_reltoken(&tty_token);
1161 return 0;
1163 case KDENABIO: /* allow io operations */
1164 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1165 if (error != 0) {
1166 lwkt_reltoken(&tty_token);
1167 return error;
1169 if (securelevel > 0) {
1170 lwkt_reltoken(&tty_token);
1171 return EPERM;
1173 #if defined(__i386__)
1174 curthread->td_lwp->lwp_md.md_regs->tf_eflags |= PSL_IOPL;
1175 #elif defined(__x86_64__)
1176 curthread->td_lwp->lwp_md.md_regs->tf_rflags |= PSL_IOPL;
1177 #endif
1178 lwkt_reltoken(&tty_token);
1179 return 0;
1181 case KDDISABIO: /* disallow io operations (default) */
1182 #if defined(__i386__)
1183 curthread->td_lwp->lwp_md.md_regs->tf_eflags &= ~PSL_IOPL;
1184 #elif defined(__x86_64__)
1185 curthread->td_lwp->lwp_md.md_regs->tf_rflags &= ~PSL_IOPL;
1186 #endif
1187 lwkt_reltoken(&tty_token);
1188 return 0;
1190 case KDSKBSTATE: /* set keyboard state (locks) */
1191 if (*(int *)data & ~LOCK_MASK) {
1192 lwkt_reltoken(&tty_token);
1193 return EINVAL;
1195 syscons_lock();
1196 scp->status &= ~LOCK_MASK;
1197 scp->status |= *(int *)data;
1198 syscons_unlock();
1199 if (scp == sc->cur_scp)
1200 update_kbd_state(scp, scp->status, LOCK_MASK, FALSE);
1201 lwkt_reltoken(&tty_token);
1202 return 0;
1204 case KDGKBSTATE: /* get keyboard state (locks) */
1205 if (scp == sc->cur_scp)
1206 save_kbd_state(scp, FALSE);
1207 *(int *)data = scp->status & LOCK_MASK;
1208 lwkt_reltoken(&tty_token);
1209 return 0;
1211 case KDGETREPEAT: /* get keyboard repeat & delay rates */
1212 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */
1213 error = kbd_ioctl(sc->kbd, cmd, data);
1214 if (error == ENOIOCTL)
1215 error = ENODEV;
1216 lwkt_reltoken(&tty_token);
1217 return error;
1219 case KDSETRAD: /* set keyboard repeat & delay rates (old) */
1220 if (*(int *)data & ~0x7f) {
1221 lwkt_reltoken(&tty_token);
1222 return EINVAL;
1224 error = kbd_ioctl(sc->kbd, cmd, data);
1225 if (error == ENOIOCTL)
1226 error = ENODEV;
1227 lwkt_reltoken(&tty_token);
1228 return error;
1230 case KDSKBMODE: /* set keyboard mode */
1231 switch (*(int *)data) {
1232 case K_XLATE: /* switch to XLT ascii mode */
1233 case K_RAW: /* switch to RAW scancode mode */
1234 case K_CODE: /* switch to CODE mode */
1235 scp->kbd_mode = *(int *)data;
1236 if (scp == sc->cur_scp)
1237 kbd_ioctl(sc->kbd, cmd, data);
1238 lwkt_reltoken(&tty_token);
1239 return 0;
1240 default:
1241 lwkt_reltoken(&tty_token);
1242 return EINVAL;
1244 /* NOT REACHED */
1246 case KDGKBMODE: /* get keyboard mode */
1247 *(int *)data = scp->kbd_mode;
1248 lwkt_reltoken(&tty_token);
1249 return 0;
1251 case KDGKBINFO:
1252 error = kbd_ioctl(sc->kbd, cmd, data);
1253 if (error == ENOIOCTL)
1254 error = ENODEV;
1255 lwkt_reltoken(&tty_token);
1256 return error;
1258 case KDMKTONE: /* sound the bell */
1259 syscons_lock();
1260 if (*(int*)data)
1261 sc_bell(scp, (*(int*)data)&0xffff,
1262 (((*(int*)data)>>16)&0xffff)*hz/1000);
1263 else
1264 sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1265 syscons_unlock();
1266 lwkt_reltoken(&tty_token);
1267 return 0;
1269 case KIOCSOUND: /* make tone (*data) hz */
1270 syscons_lock();
1271 if (scp == sc->cur_scp) {
1272 if (*(int *)data) {
1273 error = sc_tone(*(int *)data);
1274 } else {
1275 error = sc_tone(0);
1277 } else {
1278 error = 0;
1280 syscons_unlock();
1281 lwkt_reltoken(&tty_token);
1282 return error;
1284 case KDGKBTYPE: /* get keyboard type */
1285 error = kbd_ioctl(sc->kbd, cmd, data);
1286 if (error == ENOIOCTL) {
1287 /* always return something? XXX */
1288 *(int *)data = 0;
1290 lwkt_reltoken(&tty_token);
1291 return 0;
1293 case KDSETLED: /* set keyboard LED status */
1294 if (*(int *)data & ~LED_MASK) { /* FIXME: LOCK_MASK? */
1295 lwkt_reltoken(&tty_token);
1296 return EINVAL;
1298 syscons_lock();
1299 scp->status &= ~LED_MASK;
1300 scp->status |= *(int *)data;
1301 syscons_unlock();
1302 if (scp == sc->cur_scp)
1303 update_kbd_leds(scp, scp->status);
1304 lwkt_reltoken(&tty_token);
1305 return 0;
1307 case KDGETLED: /* get keyboard LED status */
1308 if (scp == sc->cur_scp)
1309 save_kbd_state(scp, FALSE);
1310 *(int *)data = scp->status & LED_MASK;
1311 lwkt_reltoken(&tty_token);
1312 return 0;
1314 case KBADDKBD: /* add/remove keyboard to/from mux */
1315 case KBRELKBD:
1316 error = kbd_ioctl(sc->kbd, cmd, data);
1317 if (error == ENOIOCTL)
1318 error = ENODEV;
1319 lwkt_reltoken(&tty_token);
1320 return error;
1322 case CONS_SETKBD: /* set the new keyboard */
1324 keyboard_t *newkbd;
1326 newkbd = kbd_get_keyboard(*(int *)data);
1327 if (newkbd == NULL) {
1328 lwkt_reltoken(&tty_token);
1329 return EINVAL;
1331 error = 0;
1332 if (sc->kbd != newkbd) {
1333 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1334 (void *)&sc->keyboard, sckbdevent, sc);
1335 /* i == newkbd->kb_index */
1336 if (i >= 0) {
1337 if (sc->kbd != NULL) {
1338 save_kbd_state(sc->cur_scp, FALSE);
1339 kbd_release(sc->kbd, (void *)&sc->keyboard);
1341 syscons_lock();
1342 sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1343 sc->keyboard = i;
1344 syscons_unlock();
1345 kbd_ioctl(sc->kbd, KDSKBMODE,
1346 (caddr_t)&sc->cur_scp->kbd_mode);
1347 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1348 LOCK_MASK, FALSE);
1349 } else {
1350 error = EPERM; /* XXX */
1353 lwkt_reltoken(&tty_token);
1354 return error;
1357 case CONS_RELKBD: /* release the current keyboard */
1358 error = 0;
1359 if (sc->kbd != NULL) {
1360 save_kbd_state(sc->cur_scp, FALSE);
1361 error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1362 if (error == 0) {
1363 syscons_lock();
1364 sc->kbd = NULL;
1365 sc->keyboard = -1;
1366 syscons_unlock();
1369 lwkt_reltoken(&tty_token);
1370 return error;
1372 case CONS_GETTERM: /* get the current terminal emulator info */
1374 sc_term_sw_t *sw;
1376 if (((term_info_t *)data)->ti_index == 0) {
1377 sw = scp->tsw;
1378 } else {
1379 sw = sc_term_match_by_number(((term_info_t *)data)->ti_index);
1381 if (sw != NULL) {
1382 strncpy(((term_info_t *)data)->ti_name, sw->te_name,
1383 sizeof(((term_info_t *)data)->ti_name));
1384 strncpy(((term_info_t *)data)->ti_desc, sw->te_desc,
1385 sizeof(((term_info_t *)data)->ti_desc));
1386 ((term_info_t *)data)->ti_flags = 0;
1387 lwkt_reltoken(&tty_token);
1388 return 0;
1389 } else {
1390 ((term_info_t *)data)->ti_name[0] = '\0';
1391 ((term_info_t *)data)->ti_desc[0] = '\0';
1392 ((term_info_t *)data)->ti_flags = 0;
1393 lwkt_reltoken(&tty_token);
1394 return EINVAL;
1398 case CONS_SETTERM: /* set the current terminal emulator */
1399 syscons_lock();
1400 error = sc_init_emulator(scp, ((term_info_t *)data)->ti_name);
1401 /* FIXME: what if scp == sc_console! XXX */
1402 syscons_unlock();
1403 lwkt_reltoken(&tty_token);
1404 return error;
1406 case GIO_SCRNMAP: /* get output translation table */
1407 bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
1408 lwkt_reltoken(&tty_token);
1409 return 0;
1411 case PIO_SCRNMAP: /* set output translation table */
1412 bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1413 for (i=0; i<sizeof(sc->scr_map); i++) {
1414 sc->scr_rmap[sc->scr_map[i]] = i;
1416 lwkt_reltoken(&tty_token);
1417 return 0;
1419 case GIO_KEYMAP: /* get keyboard translation table */
1420 case PIO_KEYMAP: /* set keyboard translation table */
1421 case GIO_DEADKEYMAP: /* get accent key translation table */
1422 case PIO_DEADKEYMAP: /* set accent key translation table */
1423 case GETFKEY: /* get function key string */
1424 case SETFKEY: /* set function key string */
1425 error = kbd_ioctl(sc->kbd, cmd, data);
1426 if (error == ENOIOCTL)
1427 error = ENODEV;
1428 lwkt_reltoken(&tty_token);
1429 return error;
1431 #ifndef SC_NO_FONT_LOADING
1433 case PIO_FONT8x8: /* set 8x8 dot font */
1434 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1435 lwkt_reltoken(&tty_token);
1436 return ENXIO;
1438 syscons_lock();
1439 bcopy(data, sc->font_8, 8*256);
1440 sc->fonts_loaded |= FONT_8;
1442 * FONT KLUDGE
1443 * Always use the font page #0. XXX
1444 * Don't load if the current font size is not 8x8.
1446 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_height < 14))
1447 sc_load_font(sc->cur_scp, 0, 8, sc->font_8, 0, 256);
1448 syscons_unlock();
1449 lwkt_reltoken(&tty_token);
1450 return 0;
1452 case GIO_FONT8x8: /* get 8x8 dot font */
1453 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1454 lwkt_reltoken(&tty_token);
1455 return ENXIO;
1457 if (sc->fonts_loaded & FONT_8) {
1458 bcopy(sc->font_8, data, 8*256);
1459 lwkt_reltoken(&tty_token);
1460 return 0;
1462 else {
1463 lwkt_reltoken(&tty_token);
1464 return ENXIO;
1467 case PIO_FONT8x14: /* set 8x14 dot font */
1468 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1469 lwkt_reltoken(&tty_token);
1470 return ENXIO;
1472 syscons_lock();
1473 bcopy(data, sc->font_14, 14*256);
1474 sc->fonts_loaded |= FONT_14;
1476 * FONT KLUDGE
1477 * Always use the font page #0. XXX
1478 * Don't load if the current font size is not 8x14.
1480 if (ISTEXTSC(sc->cur_scp)
1481 && (sc->cur_scp->font_height >= 14)
1482 && (sc->cur_scp->font_height < 16)) {
1483 sc_load_font(sc->cur_scp, 0, 14, sc->font_14, 0, 256);
1485 syscons_unlock();
1486 lwkt_reltoken(&tty_token);
1487 return 0;
1489 case GIO_FONT8x14: /* get 8x14 dot font */
1490 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1491 lwkt_reltoken(&tty_token);
1492 return ENXIO;
1494 if (sc->fonts_loaded & FONT_14) {
1495 bcopy(sc->font_14, data, 14*256);
1496 lwkt_reltoken(&tty_token);
1497 return 0;
1499 else {
1500 lwkt_reltoken(&tty_token);
1501 return ENXIO;
1504 case PIO_FONT8x16: /* set 8x16 dot font */
1505 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1506 lwkt_reltoken(&tty_token);
1507 return ENXIO;
1509 syscons_lock();
1510 bcopy(data, sc->font_16, 16*256);
1511 sc->fonts_loaded |= FONT_16;
1513 * FONT KLUDGE
1514 * Always use the font page #0. XXX
1515 * Don't load if the current font size is not 8x16.
1517 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_height >= 16))
1518 sc_load_font(sc->cur_scp, 0, 16, sc->font_16, 0, 256);
1519 syscons_unlock();
1520 lwkt_reltoken(&tty_token);
1521 return 0;
1523 case GIO_FONT8x16: /* get 8x16 dot font */
1524 if (!ISFONTAVAIL(sc->adp->va_flags)) {
1525 lwkt_reltoken(&tty_token);
1526 return ENXIO;
1528 if (sc->fonts_loaded & FONT_16) {
1529 bcopy(sc->font_16, data, 16*256);
1530 lwkt_reltoken(&tty_token);
1531 return 0;
1533 else {
1534 lwkt_reltoken(&tty_token);
1535 return ENXIO;
1538 #endif /* SC_NO_FONT_LOADING */
1540 default:
1541 break;
1544 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, ap->a_cred);
1545 if (error != ENOIOCTL) {
1546 lwkt_reltoken(&tty_token);
1547 return(error);
1549 error = ttioctl(tp, cmd, data, flag);
1550 if (error != ENOIOCTL) {
1551 lwkt_reltoken(&tty_token);
1552 return(error);
1554 lwkt_reltoken(&tty_token);
1555 return(ENOTTY);
1558 static void
1559 scstart(struct tty *tp)
1561 struct clist *rbp;
1562 int len;
1563 u_char buf[PCBURST];
1564 scr_stat *scp = SC_STAT(tp->t_dev);
1566 syscons_lock();
1567 if (scp->status & SLKED ||
1568 (scp == scp->sc->cur_scp && scp->sc->blink_in_progress))
1570 syscons_unlock();
1571 return;
1573 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1574 tp->t_state |= TS_BUSY;
1575 rbp = &tp->t_outq;
1576 while (rbp->c_cc) {
1577 len = q_to_b(rbp, buf, PCBURST);
1578 sc_puts(scp, buf, len);
1580 tp->t_state &= ~TS_BUSY;
1581 syscons_unlock();
1582 ttwwakeup(tp);
1583 } else {
1584 syscons_unlock();
1588 static void
1589 sccnprobe(struct consdev *cp)
1591 int unit;
1592 int flags;
1594 cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1596 /* a video card is always required */
1597 if (!scvidprobe(unit, flags, TRUE))
1598 cp->cn_pri = CN_DEAD;
1600 /* syscons will become console even when there is no keyboard */
1601 sckbdprobe(unit, flags, TRUE);
1603 if (cp->cn_pri == CN_DEAD) {
1604 return;
1607 /* initialize required fields */
1608 cp->cn_probegood = 1;
1611 static void
1612 sccninit(struct consdev *cp)
1614 int unit;
1615 int flags;
1617 sc_get_cons_priority(&unit, &flags);
1618 scinit(unit, flags | SC_KERNEL_CONSOLE);
1619 sc_console_unit = unit;
1620 sc_console = sc_get_softc(unit, SC_KERNEL_CONSOLE)->console_scp;
1623 static void
1624 sccninit_fini(struct consdev *cp)
1626 if (cctl_dev == NULL)
1627 kprintf("sccninit_fini: WARNING: cctl_dev is NULL!\n");
1628 cp->cn_dev = cctl_dev;
1631 static void
1632 sccnterm(struct consdev *cp)
1634 /* we are not the kernel console any more, release everything */
1636 if (sc_console_unit < 0)
1637 return; /* shouldn't happen */
1639 #if 0 /* XXX */
1640 syscons_lock();
1641 sc_clear_screen(sc_console);
1642 sccnupdate(sc_console);
1643 syscons_unlock();
1644 #endif
1645 scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1646 sc_console_unit = -1;
1647 sc_console = NULL;
1651 * Console path - cannot block!
1653 static void
1654 sccnputc(void *private, int c)
1656 u_char buf[1];
1657 scr_stat *scp = sc_console;
1658 void *save;
1659 #ifndef SC_NO_HISTORY
1660 #if 0
1661 struct tty *tp;
1662 #endif
1663 #endif /* !SC_NO_HISTORY */
1665 /* assert(sc_console != NULL) */
1667 syscons_lock();
1668 #ifndef SC_NO_HISTORY
1669 if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1670 scp->status &= ~SLKED;
1671 #if 0
1672 /* This can block, illegal in the console path */
1673 update_kbd_state(scp, scp->status, SLKED, TRUE);
1674 #endif
1675 if (scp->status & BUFFER_SAVED) {
1676 if (!sc_hist_restore(scp))
1677 sc_remove_cutmarking(scp);
1678 scp->status &= ~BUFFER_SAVED;
1679 scp->status |= CURSOR_ENABLED;
1680 sc_draw_cursor_image(scp);
1682 #if 0
1683 tp = VIRTUAL_TTY(scp->sc, scp->index);
1684 /* This can block, illegal in the console path */
1685 if (ISTTYOPEN(tp)) {
1686 scstart(tp);
1688 #endif
1690 #endif /* !SC_NO_HISTORY */
1692 save = scp->ts;
1693 if (kernel_console_ts != NULL)
1694 scp->ts = kernel_console_ts;
1695 buf[0] = c;
1696 sc_puts(scp, buf, 1);
1697 scp->ts = save;
1699 sccnupdate(scp);
1700 syscons_unlock();
1704 * Console path - cannot block!
1706 static int
1707 sccngetc(void *private)
1709 return sccngetch(0);
1713 * Console path - cannot block!
1715 static int
1716 sccncheckc(void *private)
1718 return sccngetch(SCGETC_NONBLOCK);
1721 static void
1722 sccndbctl(void *private, int on)
1724 /* assert(sc_console_unit >= 0) */
1725 /* try to switch to the kernel console screen */
1726 if (on && debugger == 0) {
1728 * TRY to make sure the screen saver is stopped,
1729 * and the screen is updated before switching to
1730 * the vty0.
1732 scrn_timer(NULL);
1733 if (!cold
1734 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
1735 && sc_console->smode.mode == VT_AUTO) {
1736 sc_console->sc->cur_scp->status |= MOUSE_HIDDEN;
1737 syscons_lock();
1738 sc_switch_scr(sc_console->sc, sc_console->index);
1739 syscons_unlock();
1742 if (on)
1743 ++debugger;
1744 else
1745 --debugger;
1749 * Console path - cannot block!
1751 static int
1752 sccngetch(int flags)
1754 static struct fkeytab fkey;
1755 static int fkeycp;
1756 scr_stat *scp;
1757 u_char *p;
1758 int cur_mode;
1759 int c;
1761 syscons_lock();
1762 /* assert(sc_console != NULL) */
1765 * Stop the screen saver and update the screen if necessary.
1766 * What if we have been running in the screen saver code... XXX
1768 sc_touch_scrn_saver();
1769 scp = sc_console->sc->cur_scp; /* XXX */
1770 sccnupdate(scp);
1771 syscons_unlock();
1773 if (fkeycp < fkey.len) {
1774 return fkey.str[fkeycp++];
1777 if (scp->sc->kbd == NULL) {
1778 return -1;
1782 * Make sure the keyboard is accessible even when the kbd device
1783 * driver is disabled.
1785 crit_enter();
1786 kbd_enable(scp->sc->kbd);
1788 /* we shall always use the keyboard in the XLATE mode here */
1789 cur_mode = scp->kbd_mode;
1790 scp->kbd_mode = K_XLATE;
1791 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1793 kbd_poll(scp->sc->kbd, TRUE);
1794 c = scgetc(scp->sc, SCGETC_CN | flags);
1795 kbd_poll(scp->sc->kbd, FALSE);
1797 scp->kbd_mode = cur_mode;
1798 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1799 kbd_disable(scp->sc->kbd);
1800 crit_exit();
1802 switch (KEYFLAGS(c)) {
1803 case 0: /* normal char */
1804 return KEYCHAR(c);
1805 case FKEY: /* function key */
1806 p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
1807 fkey.len = fkeycp;
1808 if ((p != NULL) && (fkey.len > 0)) {
1809 bcopy(p, fkey.str, fkey.len);
1810 fkeycp = 1;
1811 return fkey.str[0];
1813 return c; /* XXX */
1814 case NOKEY:
1815 case ERRKEY:
1816 default:
1817 return -1;
1819 /* NOT REACHED */
1822 static void
1823 sccnupdate(scr_stat *scp)
1825 /* this is a cut-down version of scrn_timer()... */
1827 if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress) {
1828 return;
1831 if (debugger > 0 || panicstr || shutdown_in_progress) {
1832 sc_touch_scrn_saver();
1833 } else if (scp != scp->sc->cur_scp) {
1834 return;
1837 if (!run_scrn_saver)
1838 scp->sc->flags &= ~SC_SCRN_IDLE;
1839 #if NSPLASH > 0
1841 * This is a hard path, we cannot call stop_scrn_saver() here.
1843 if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1844 if (scp->sc->flags & SC_SCRN_BLANKED) {
1845 sc_touch_scrn_saver();
1846 /*stop_scrn_saver(scp->sc, current_saver);*/
1848 #endif /* NSPLASH */
1850 if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
1851 || scp->sc->switch_in_progress) {
1852 return;
1855 * FIXME: unlike scrn_timer(), we call scrn_update() from here even
1856 * when write_in_progress is non-zero. XXX
1859 if (!ISGRAPHSC(scp) && !(scp->sc->flags & SC_SCRN_BLANKED))
1860 scrn_update(scp, TRUE);
1863 static void
1864 scrn_timer(void *arg)
1866 static int kbd_interval = 0;
1867 struct timeval tv;
1868 sc_softc_t *sc;
1869 scr_stat *scp;
1870 int again;
1873 * Setup depending on who called us
1875 again = (arg != NULL);
1876 if (arg != NULL) {
1877 sc = (sc_softc_t *)arg;
1878 } else if (sc_console != NULL) {
1879 sc = sc_console->sc;
1880 } else {
1881 return;
1885 * Don't do anything when we are performing some I/O operations.
1886 * (These are initiated by the frontend?)
1888 if (sc->font_loading_in_progress || sc->videoio_in_progress) {
1889 if (again)
1890 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
1891 return;
1895 * Try to allocate a keyboard automatically
1897 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
1898 if (++kbd_interval >= 25) {
1899 sc->keyboard = sc_allocate_keyboard(sc, -1);
1900 if (sc->keyboard >= 0) {
1901 sc->kbd = kbd_get_keyboard(sc->keyboard);
1902 kbd_ioctl(sc->kbd, KDSKBMODE,
1903 (caddr_t)&sc->cur_scp->kbd_mode);
1904 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1905 LOCK_MASK, FALSE);
1907 kbd_interval = 0;
1912 * Should we stop the screen saver? We need the syscons_lock
1913 * for most of this stuff.
1915 getmicrouptime(&tv);
1917 if (syscons_lock_nonblock() != 0) {
1918 /* failed to get the lock */
1919 if (again)
1920 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
1921 return;
1923 /* successful lock */
1925 if (debugger > 0 || panicstr || shutdown_in_progress)
1926 sc_touch_scrn_saver();
1927 if (run_scrn_saver) {
1928 if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
1929 sc->flags |= SC_SCRN_IDLE;
1930 else
1931 sc->flags &= ~SC_SCRN_IDLE;
1932 } else {
1933 sc->scrn_time_stamp = tv.tv_sec;
1934 sc->flags &= ~SC_SCRN_IDLE;
1935 if (scrn_blank_time > 0)
1936 run_scrn_saver = TRUE;
1938 #if NSPLASH > 0
1939 if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE))
1940 if (sc->flags & SC_SCRN_BLANKED)
1941 stop_scrn_saver(sc, current_saver);
1942 #endif /* NSPLASH */
1944 /* should we just return ? */
1945 if (sc->blink_in_progress || sc->switch_in_progress ||
1946 sc->write_in_progress)
1948 syscons_unlock();
1949 if (again)
1950 callout_reset(&sc->scrn_timer_ch, hz / 10, scrn_timer, sc);
1951 return;
1954 /* Update the screen */
1955 scp = sc->cur_scp; /* cur_scp may have changed... */
1956 if (!ISGRAPHSC(scp) && !(sc->flags & SC_SCRN_BLANKED))
1957 scrn_update(scp, TRUE);
1959 #if NSPLASH > 0
1960 /* should we activate the screen saver? */
1961 if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
1962 if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
1963 (*current_saver)(sc, TRUE);
1964 #endif /* NSPLASH */
1966 syscons_unlock();
1967 if (again)
1968 callout_reset(&sc->scrn_timer_ch, hz / 25, scrn_timer, sc);
1971 static int
1972 and_region(int *s1, int *e1, int s2, int e2)
1974 if (*e1 < s2 || e2 < *s1)
1975 return FALSE;
1976 *s1 = imax(*s1, s2);
1977 *e1 = imin(*e1, e2);
1978 return TRUE;
1981 static void
1982 scrn_update(scr_stat *scp, int show_cursor)
1984 int start;
1985 int end;
1986 int s;
1987 int e;
1989 /* assert(scp == scp->sc->cur_scp) */
1991 ++scp->sc->videoio_in_progress;
1993 #ifndef SC_NO_CUTPASTE
1994 /* remove the previous mouse pointer image if necessary */
1995 if (scp->status & MOUSE_VISIBLE) {
1996 s = scp->mouse_pos;
1997 e = scp->mouse_pos + scp->xsize + 1;
1998 if ((scp->status & (MOUSE_MOVED | MOUSE_HIDDEN))
1999 || and_region(&s, &e, scp->start, scp->end)
2000 || ((scp->status & CURSOR_ENABLED) &&
2001 (scp->cursor_pos != scp->cursor_oldpos) &&
2002 (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos)
2003 || and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)))) {
2004 sc_remove_mouse_image(scp);
2005 if (scp->end >= scp->xsize*scp->ysize)
2006 scp->end = scp->xsize*scp->ysize - 1;
2009 #endif /* !SC_NO_CUTPASTE */
2011 #if 1
2012 /* debug: XXX */
2013 if (scp->end >= scp->xsize*scp->ysize) {
2014 kprintf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end);
2015 scp->end = scp->xsize*scp->ysize - 1;
2017 if (scp->start < 0) {
2018 kprintf("scrn_update(): scp->start %d < 0\n", scp->start);
2019 scp->start = 0;
2021 #endif
2023 /* update screen image */
2024 if (scp->start <= scp->end) {
2025 if (scp->mouse_cut_end >= 0) {
2026 /* there is a marked region for cut & paste */
2027 if (scp->mouse_cut_start <= scp->mouse_cut_end) {
2028 start = scp->mouse_cut_start;
2029 end = scp->mouse_cut_end;
2030 } else {
2031 start = scp->mouse_cut_end;
2032 end = scp->mouse_cut_start - 1;
2034 s = start;
2035 e = end;
2036 /* does the cut-mark region overlap with the update region? */
2037 if (and_region(&s, &e, scp->start, scp->end)) {
2038 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
2039 s = 0;
2040 e = start - 1;
2041 if (and_region(&s, &e, scp->start, scp->end))
2042 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
2043 s = end + 1;
2044 e = scp->xsize*scp->ysize - 1;
2045 if (and_region(&s, &e, scp->start, scp->end))
2046 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
2047 } else {
2048 (*scp->rndr->draw)(scp, scp->start,
2049 scp->end - scp->start + 1, FALSE);
2051 } else {
2052 (*scp->rndr->draw)(scp, scp->start,
2053 scp->end - scp->start + 1, FALSE);
2057 /* we are not to show the cursor and the mouse pointer... */
2058 if (!show_cursor) {
2059 scp->end = 0;
2060 scp->start = scp->xsize*scp->ysize - 1;
2061 --scp->sc->videoio_in_progress;
2062 return;
2065 /* update cursor image */
2066 if (scp->status & CURSOR_ENABLED) {
2067 s = scp->start;
2068 e = scp->end;
2069 /* did cursor move since last time ? */
2070 if (scp->cursor_pos != scp->cursor_oldpos) {
2071 /* do we need to remove old cursor image ? */
2072 if (!and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos))
2073 sc_remove_cursor_image(scp);
2074 sc_draw_cursor_image(scp);
2075 } else {
2076 if (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos))
2077 /* cursor didn't move, but has been overwritten */
2078 sc_draw_cursor_image(scp);
2079 else if (scp->sc->flags & SC_BLINK_CURSOR)
2080 /* if it's a blinking cursor, update it */
2081 (*scp->rndr->blink_cursor)(scp, scp->cursor_pos,
2082 sc_inside_cutmark(scp,
2083 scp->cursor_pos));
2087 #ifndef SC_NO_CUTPASTE
2088 /* update "pseudo" mouse pointer image */
2089 if (scp->sc->flags & SC_MOUSE_ENABLED) {
2090 if (!(scp->status & (MOUSE_VISIBLE | MOUSE_HIDDEN))) {
2091 scp->status &= ~MOUSE_MOVED;
2092 sc_draw_mouse_image(scp);
2095 #endif /* SC_NO_CUTPASTE */
2097 scp->end = 0;
2098 scp->start = scp->xsize*scp->ysize - 1;
2100 --scp->sc->videoio_in_progress;
2103 #if NSPLASH > 0
2104 static int
2105 scsplash_callback(int event, void *arg)
2107 sc_softc_t *sc;
2108 int error;
2110 sc = (sc_softc_t *)arg;
2112 switch (event) {
2113 case SPLASH_INIT:
2114 if (add_scrn_saver(scsplash_saver) == 0) {
2115 sc->flags &= ~SC_SAVER_FAILED;
2116 run_scrn_saver = TRUE;
2117 if (cold && !(boothowto & (RB_VERBOSE | RB_CONFIG))) {
2118 scsplash_stick(TRUE);
2119 (*current_saver)(sc, TRUE);
2122 return 0;
2124 case SPLASH_TERM:
2125 if (current_saver == scsplash_saver) {
2126 scsplash_stick(FALSE);
2127 error = remove_scrn_saver(scsplash_saver);
2128 if (error) {
2129 return error;
2132 return 0;
2134 default:
2135 return EINVAL;
2139 static void
2140 scsplash_saver(sc_softc_t *sc, int show)
2142 static int busy = FALSE;
2143 scr_stat *scp;
2145 if (busy)
2146 return;
2147 busy = TRUE;
2149 scp = sc->cur_scp;
2150 if (show) {
2151 if (!(sc->flags & SC_SAVER_FAILED)) {
2152 if (!(sc->flags & SC_SCRN_BLANKED))
2153 set_scrn_saver_mode(scp, -1, NULL, 0);
2154 switch (splash(sc->adp, TRUE)) {
2155 case 0: /* succeeded */
2156 break;
2157 case EAGAIN: /* try later */
2158 restore_scrn_saver_mode(scp, FALSE);
2159 sc_touch_scrn_saver(); /* XXX */
2160 break;
2161 default:
2162 sc->flags |= SC_SAVER_FAILED;
2163 scsplash_stick(FALSE);
2164 restore_scrn_saver_mode(scp, TRUE);
2165 kprintf("scsplash_saver(): failed to put up the image\n");
2166 break;
2169 } else if (!sticky_splash) {
2170 if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
2171 restore_scrn_saver_mode(scp, TRUE);
2173 busy = FALSE;
2176 static int
2177 add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
2179 #if 0
2180 int error;
2182 if (current_saver != none_saver) {
2183 error = remove_scrn_saver(current_saver);
2184 if (error)
2185 return error;
2187 #endif
2188 if (current_saver != none_saver) {
2189 return EBUSY;
2192 run_scrn_saver = FALSE;
2193 saver_mode = CONS_LKM_SAVER;
2194 current_saver = this_saver;
2195 return 0;
2198 static int
2199 remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
2201 if (current_saver != this_saver)
2202 return EINVAL;
2204 #if 0
2206 * In order to prevent `current_saver' from being called by
2207 * the timeout routine `scrn_timer()' while we manipulate
2208 * the saver list, we shall set `current_saver' to `none_saver'
2209 * before stopping the current saver, rather than blocking by `splXX()'.
2211 current_saver = none_saver;
2212 if (scrn_blanked)
2213 stop_scrn_saver(this_saver);
2214 #endif
2215 /* unblank all blanked screens */
2216 wait_scrn_saver_stop(NULL);
2217 if (scrn_blanked) {
2218 return EBUSY;
2221 current_saver = none_saver;
2222 return 0;
2225 static int
2226 set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
2229 /* assert(scp == scp->sc->cur_scp) */
2230 crit_enter();
2231 if (!ISGRAPHSC(scp))
2232 sc_remove_cursor_image(scp);
2233 scp->splash_save_mode = scp->mode;
2234 scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
2235 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
2236 scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
2237 scp->sc->flags |= SC_SCRN_BLANKED;
2238 ++scrn_blanked;
2239 crit_exit();
2240 if (mode < 0) {
2241 return 0;
2243 scp->mode = mode;
2244 if (set_mode(scp) == 0) {
2245 if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS)
2246 scp->status |= GRAPHICS_MODE;
2247 #ifndef SC_NO_PALETTE_LOADING
2248 if (pal != NULL)
2249 load_palette(scp->sc->adp, pal);
2250 #endif
2251 sc_set_border(scp, border);
2252 return 0;
2253 } else {
2254 crit_enter();
2255 scp->mode = scp->splash_save_mode;
2256 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2257 scp->status |= scp->splash_save_status;
2258 crit_exit();
2259 return 1;
2261 /* NOTREACHED */
2264 static int
2265 restore_scrn_saver_mode(scr_stat *scp, int changemode)
2267 int mode;
2268 int status;
2270 /* assert(scp == scp->sc->cur_scp) */
2271 crit_enter();
2272 mode = scp->mode;
2273 status = scp->status;
2274 scp->mode = scp->splash_save_mode;
2275 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2276 scp->status |= scp->splash_save_status;
2277 scp->sc->flags &= ~SC_SCRN_BLANKED;
2278 if (!changemode) {
2279 if (!ISGRAPHSC(scp))
2280 sc_draw_cursor_image(scp);
2281 --scrn_blanked;
2282 crit_exit();
2283 return 0;
2285 if (set_mode(scp) == 0) {
2286 #ifndef SC_NO_PALETTE_LOADING
2287 load_palette(scp->sc->adp, scp->sc->palette);
2288 #endif
2289 --scrn_blanked;
2290 crit_exit();
2291 return 0;
2292 } else {
2293 scp->mode = mode;
2294 scp->status = status;
2295 crit_exit();
2296 return 1;
2298 /* NOTREACHED */
2301 static void
2302 stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
2304 (*saver)(sc, FALSE);
2305 run_scrn_saver = FALSE;
2306 /* the screen saver may have chosen not to stop after all... */
2307 if (sc->flags & SC_SCRN_BLANKED) {
2308 return;
2311 mark_all(sc->cur_scp);
2312 if (sc->delayed_next_scr)
2313 sc_switch_scr(sc, sc->delayed_next_scr - 1);
2314 wakeup((caddr_t)&scrn_blanked);
2317 static int
2318 wait_scrn_saver_stop(sc_softc_t *sc)
2320 int error = 0;
2322 while (scrn_blanked > 0) {
2323 run_scrn_saver = FALSE;
2324 if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
2325 error = 0;
2326 break;
2328 error = tsleep((caddr_t)&scrn_blanked, PCATCH, "scrsav", 0);
2329 /* May return ERESTART */
2330 if (error)
2331 break;
2333 run_scrn_saver = FALSE;
2334 return error;
2336 #endif /* NSPLASH */
2338 void
2339 sc_touch_scrn_saver(void)
2341 scsplash_stick(FALSE);
2342 run_scrn_saver = FALSE;
2346 sc_switch_scr(sc_softc_t *sc, u_int next_scr)
2348 scr_stat *cur_scp;
2349 struct tty *tp;
2351 DPRINTF(5, ("sc0: sc_switch_scr() %d ", next_scr + 1));
2353 /* prevent switch if previously requested */
2354 if (sc->flags & SC_SCRN_VTYLOCK) {
2355 sc_bell(sc->cur_scp, sc->cur_scp->bell_pitch,
2356 sc->cur_scp->bell_duration);
2357 return EPERM;
2360 /* delay switch if the screen is blanked or being updated */
2361 if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2362 || sc->blink_in_progress || sc->videoio_in_progress) {
2363 sc->delayed_next_scr = next_scr + 1;
2364 sc_touch_scrn_saver();
2365 DPRINTF(5, ("switch delayed\n"));
2366 return 0;
2369 cur_scp = sc->cur_scp;
2372 * we are in the middle of the vty switching process...
2374 * This may be in the console path, be very careful. pfindn() is
2375 * still going to use a spinlock but it no longer uses tokens so
2376 * we should be ok.
2378 if (sc->switch_in_progress &&
2379 (cur_scp->smode.mode == VT_PROCESS) &&
2380 cur_scp->proc) {
2381 if (cur_scp->proc != pfindn(cur_scp->pid)) {
2383 * The controlling process has died!!. Do some clean up.
2384 * NOTE:`cur_scp->proc' and `cur_scp->smode.mode'
2385 * are not reset here yet; they will be cleared later.
2387 DPRINTF(5, ("cur_scp controlling process %d died, ", cur_scp->pid));
2388 if (cur_scp->status & SWITCH_WAIT_REL) {
2390 * Force the previous switch to finish, but return now
2391 * with error.
2394 DPRINTF(5, ("reset WAIT_REL, "));
2395 finish_vt_rel(cur_scp, TRUE);
2396 DPRINTF(5, ("finishing previous switch\n"));
2397 return EINVAL;
2398 } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2399 /* let's assume screen switch has been completed. */
2400 DPRINTF(5, ("reset WAIT_ACQ, "));
2401 finish_vt_acq(cur_scp);
2402 } else {
2404 * We are in between screen release and acquisition, and
2405 * reached here via scgetc() or scrn_timer() which has
2406 * interrupted exchange_scr(). Don't do anything stupid.
2408 DPRINTF(5, ("waiting nothing, "));
2410 } else {
2412 * The controlling process is alive, but not responding...
2413 * It is either buggy or it may be just taking time.
2414 * The following code is a gross kludge to cope with this
2415 * problem for which there is no clean solution. XXX
2417 if (cur_scp->status & SWITCH_WAIT_REL) {
2418 switch (sc->switch_in_progress++) {
2419 case 1:
2420 break;
2421 case 2:
2422 DPRINTF(5, ("sending relsig again, "));
2423 signal_vt_rel(cur_scp);
2424 break;
2425 case 3:
2426 break;
2427 case 4:
2428 default:
2430 * Act as if the controlling program returned
2431 * VT_FALSE.
2434 DPRINTF(5, ("force reset WAIT_REL, "));
2435 finish_vt_rel(cur_scp, FALSE);
2436 DPRINTF(5, ("act as if VT_FALSE was seen\n"));
2437 return EINVAL;
2439 } else if (cur_scp->status & SWITCH_WAIT_ACQ) {
2440 switch (sc->switch_in_progress++) {
2441 case 1:
2442 break;
2443 case 2:
2444 DPRINTF(5, ("sending acqsig again, "));
2445 signal_vt_acq(cur_scp);
2446 break;
2447 case 3:
2448 break;
2449 case 4:
2450 default:
2451 /* clear the flag and finish the previous switch */
2452 DPRINTF(5, ("force reset WAIT_ACQ, "));
2453 finish_vt_acq(cur_scp);
2454 break;
2461 * Return error if an invalid argument is given, or vty switch
2462 * is still in progress.
2464 if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2465 || sc->switch_in_progress) {
2466 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2467 DPRINTF(5, ("error 1\n"));
2468 return EINVAL;
2472 * Don't allow switching away from the graphics mode vty
2473 * if the switch mode is VT_AUTO, unless the next vty is the same
2474 * as the current or the current vty has been closed (but showing).
2476 tp = VIRTUAL_TTY(sc, cur_scp->index);
2477 if ((cur_scp->index != next_scr)
2478 && ISTTYOPEN(tp)
2479 && (cur_scp->smode.mode == VT_AUTO)
2480 && ISGRAPHSC(cur_scp)) {
2481 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2482 DPRINTF(5, ("error, graphics mode\n"));
2483 return EINVAL;
2487 * Is the wanted vty open? Don't allow switching to a closed vty.
2488 * If we are in DDB, don't switch to a vty in the VT_PROCESS mode.
2489 * Note that we always allow the user to switch to the kernel
2490 * console even if it is closed.
2492 if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2493 tp = VIRTUAL_TTY(sc, next_scr);
2494 if (!ISTTYOPEN(tp)) {
2495 sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION);
2496 DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2497 return EINVAL;
2499 if ((debugger > 0) && (SC_STAT(tp->t_dev)->smode.mode == VT_PROCESS)) {
2500 DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n"));
2501 return EINVAL;
2505 /* this is the start of vty switching process... */
2506 ++sc->switch_in_progress;
2507 sc->delayed_next_scr = 0;
2508 sc->old_scp = cur_scp;
2509 sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2510 if (sc->new_scp == sc->old_scp) {
2511 sc->switch_in_progress = 0;
2512 wakeup((caddr_t)&sc->new_scp->smode);
2513 DPRINTF(5, ("switch done (new == old)\n"));
2514 return 0;
2517 /* has controlling process died? */
2518 vt_proc_alive(sc->old_scp);
2519 vt_proc_alive(sc->new_scp);
2521 /* wait for the controlling process to release the screen, if necessary */
2522 if (signal_vt_rel(sc->old_scp)) {
2523 return 0;
2526 /* go set up the new vty screen */
2527 exchange_scr(sc);
2529 /* wake up processes waiting for this vty */
2530 wakeup((caddr_t)&sc->cur_scp->smode);
2532 /* wait for the controlling process to acknowledge, if necessary */
2533 if (signal_vt_acq(sc->cur_scp)) {
2534 return 0;
2537 sc->switch_in_progress = 0;
2538 if (sc->unit == sc_console_unit)
2539 cons_unavail = FALSE;
2540 DPRINTF(5, ("switch done\n"));
2542 return 0;
2545 static void
2546 do_switch_scr(sc_softc_t *sc)
2548 lwkt_gettoken(&tty_token);
2549 vt_proc_alive(sc->new_scp);
2551 exchange_scr(sc);
2552 /* sc->cur_scp == sc->new_scp */
2553 wakeup((caddr_t)&sc->cur_scp->smode);
2555 /* wait for the controlling process to acknowledge, if necessary */
2556 if (!signal_vt_acq(sc->cur_scp)) {
2557 sc->switch_in_progress = 0;
2558 if (sc->unit == sc_console_unit)
2559 cons_unavail = FALSE;
2561 lwkt_reltoken(&tty_token);
2564 static int
2565 vt_proc_alive(scr_stat *scp)
2567 lwkt_gettoken(&tty_token);
2568 if (scp->proc) {
2569 if (scp->proc == pfindn(scp->pid)) {
2570 lwkt_reltoken(&tty_token);
2571 return TRUE;
2573 scp->proc = NULL;
2574 scp->smode.mode = VT_AUTO;
2575 DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2577 lwkt_reltoken(&tty_token);
2578 return FALSE;
2581 static int
2582 signal_vt_rel(scr_stat *scp)
2584 struct proc *p;
2586 lwkt_gettoken(&tty_token);
2587 if (scp->smode.mode != VT_PROCESS) {
2588 lwkt_reltoken(&tty_token);
2589 return FALSE;
2591 scp->status |= SWITCH_WAIT_REL;
2592 p = scp->proc;
2593 PHOLD(p);
2594 ksignal(p, scp->smode.relsig);
2595 PRELE(p);
2596 DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2597 lwkt_reltoken(&tty_token);
2599 return TRUE;
2602 static int
2603 signal_vt_acq(scr_stat *scp)
2605 struct proc *p;
2607 lwkt_gettoken(&tty_token);
2608 if (scp->smode.mode != VT_PROCESS) {
2609 lwkt_reltoken(&tty_token);
2610 return FALSE;
2612 if (scp->sc->unit == sc_console_unit)
2613 cons_unavail = TRUE;
2614 scp->status |= SWITCH_WAIT_ACQ;
2615 p = scp->proc;
2616 PHOLD(p);
2617 ksignal(p, scp->smode.acqsig);
2618 PRELE(p);
2619 DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2620 lwkt_reltoken(&tty_token);
2622 return TRUE;
2625 static int
2626 finish_vt_rel(scr_stat *scp, int release)
2628 lwkt_gettoken(&tty_token);
2629 if (scp == scp->sc->old_scp && scp->status & SWITCH_WAIT_REL) {
2630 scp->status &= ~SWITCH_WAIT_REL;
2631 if (release)
2632 do_switch_scr(scp->sc);
2633 else
2634 scp->sc->switch_in_progress = 0;
2635 lwkt_reltoken(&tty_token);
2636 return 0;
2638 lwkt_reltoken(&tty_token);
2639 return EINVAL;
2642 static int
2643 finish_vt_acq(scr_stat *scp)
2645 lwkt_gettoken(&tty_token);
2646 if (scp == scp->sc->new_scp && scp->status & SWITCH_WAIT_ACQ) {
2647 scp->status &= ~SWITCH_WAIT_ACQ;
2648 scp->sc->switch_in_progress = 0;
2649 lwkt_reltoken(&tty_token);
2650 return 0;
2652 lwkt_reltoken(&tty_token);
2653 return EINVAL;
2656 static void
2657 exchange_scr(sc_softc_t *sc)
2659 scr_stat *scp;
2661 lwkt_gettoken(&tty_token);
2662 /* save the current state of video and keyboard */
2663 sc_move_cursor(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
2664 if (!ISGRAPHSC(sc->old_scp))
2665 sc_remove_cursor_image(sc->old_scp);
2666 if (sc->old_scp->kbd_mode == K_XLATE)
2667 save_kbd_state(sc->old_scp, TRUE);
2669 /* set up the video for the new screen */
2670 scp = sc->cur_scp = sc->new_scp;
2671 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
2672 set_mode(scp);
2673 else
2674 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2675 (void *)sc->adp->va_window, FALSE);
2676 scp->status |= MOUSE_HIDDEN;
2677 sc_update_render(scp); /* Switch to kms renderer if necessary */
2678 sc_move_cursor(scp, scp->xpos, scp->ypos);
2679 if (!ISGRAPHSC(scp))
2680 sc_set_cursor_image(scp);
2681 #ifndef SC_NO_PALETTE_LOADING
2682 if (ISGRAPHSC(sc->old_scp))
2683 load_palette(sc->adp, sc->palette);
2684 #endif
2685 sc_set_border(scp, scp->border);
2687 /* set up the keyboard for the new screen */
2688 if (sc->old_scp->kbd_mode != scp->kbd_mode)
2689 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2690 update_kbd_state(scp, scp->status, LOCK_MASK, TRUE);
2692 mark_all(scp);
2693 if (scp->sc->fbi != NULL) {
2694 scp->sc->fbi->restore(scp->sc->fbi->cookie);
2696 lwkt_reltoken(&tty_token);
2699 static void
2700 sc_puts(scr_stat *scp, u_char *buf, int len)
2702 #if NSPLASH > 0
2703 /* make screensaver happy */
2704 if (!sticky_splash && scp == scp->sc->cur_scp)
2705 run_scrn_saver = FALSE;
2706 #endif
2708 if (scp->tsw)
2709 (*scp->tsw->te_puts)(scp, buf, len);
2711 if (scp->sc->delayed_next_scr)
2712 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
2716 void
2717 sc_draw_cursor_image(scr_stat *scp)
2719 /* assert(scp == scp->sc->cur_scp); */
2720 ++scp->sc->videoio_in_progress;
2721 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
2722 scp->sc->flags & SC_BLINK_CURSOR, TRUE,
2723 sc_inside_cutmark(scp, scp->cursor_pos));
2724 scp->cursor_oldpos = scp->cursor_pos;
2725 --scp->sc->videoio_in_progress;
2728 void
2729 sc_remove_cursor_image(scr_stat *scp)
2731 /* assert(scp == scp->sc->cur_scp); */
2732 ++scp->sc->videoio_in_progress;
2733 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
2734 scp->sc->flags & SC_BLINK_CURSOR, FALSE,
2735 sc_inside_cutmark(scp, scp->cursor_oldpos));
2736 --scp->sc->videoio_in_progress;
2739 static void
2740 update_cursor_image(scr_stat *scp)
2742 int blink;
2744 if (scp->sc->flags & SC_CHAR_CURSOR) {
2745 scp->cursor_base = imax(0, scp->sc->cursor_base);
2746 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_height);
2747 } else {
2748 scp->cursor_base = 0;
2749 scp->cursor_height = scp->font_height;
2751 blink = scp->sc->flags & SC_BLINK_CURSOR;
2753 /* assert(scp == scp->sc->cur_scp); */
2754 ++scp->sc->videoio_in_progress;
2755 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
2756 sc_inside_cutmark(scp, scp->cursor_pos));
2757 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
2758 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
2759 sc_inside_cutmark(scp, scp->cursor_pos));
2760 --scp->sc->videoio_in_progress;
2763 void
2764 sc_set_cursor_image(scr_stat *scp)
2766 if (scp->sc->flags & SC_CHAR_CURSOR) {
2767 scp->cursor_base = imax(0, scp->sc->cursor_base);
2768 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_height);
2769 } else {
2770 scp->cursor_base = 0;
2771 scp->cursor_height = scp->font_height;
2774 /* assert(scp == scp->sc->cur_scp); */
2775 ++scp->sc->videoio_in_progress;
2776 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
2777 scp->sc->flags & SC_BLINK_CURSOR);
2778 --scp->sc->videoio_in_progress;
2781 static void
2782 scinit(int unit, int flags)
2785 * When syscons is being initialized as the kernel console, malloc()
2786 * is not yet functional, because various kernel structures has not been
2787 * fully initialized yet. Therefore, we need to declare the following
2788 * static buffers for the console. This is less than ideal,
2789 * but is necessry evil for the time being. XXX
2791 static scr_stat main_console;
2792 static u_short sc_buffer[ROW*COL]; /* XXX */
2793 #ifndef SC_NO_FONT_LOADING
2794 static u_char font_8[256*8];
2795 static u_char font_14[256*14];
2796 static u_char font_16[256*16];
2797 #endif
2799 sc_softc_t *sc;
2800 scr_stat *scp;
2801 video_adapter_t *adp;
2802 int col;
2803 int row;
2804 int i;
2806 /* one time initialization */
2807 if (init_done == COLD)
2808 sc_get_bios_values(&bios_value);
2809 init_done = WARM;
2812 * Allocate resources. Even if we are being called for the second
2813 * time, we must allocate them again, because they might have
2814 * disappeared...
2816 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
2817 adp = NULL;
2818 if (sc->adapter >= 0) {
2819 vid_release(sc->adp, (void *)&sc->adapter);
2820 adp = sc->adp;
2821 sc->adp = NULL;
2823 if (sc->keyboard >= 0) {
2824 DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
2825 i = kbd_release(sc->kbd, (void *)&sc->keyboard);
2826 DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
2827 if (sc->kbd != NULL) {
2828 DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, unit:%d, flags:0x%x\n",
2829 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags));
2831 sc->kbd = NULL;
2833 sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
2834 sc->adp = vid_get_adapter(sc->adapter);
2835 /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
2836 sc->keyboard = sc_allocate_keyboard(sc, unit);
2837 DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
2838 sc->kbd = kbd_get_keyboard(sc->keyboard);
2839 if (sc->kbd != NULL) {
2840 DPRINTF(1, ("sc%d: kbd index:%d, unit:%d, flags:0x%x\n",
2841 unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags));
2844 if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
2846 sc->initial_mode = sc->adp->va_initial_mode;
2848 #ifndef SC_NO_FONT_LOADING
2849 if (flags & SC_KERNEL_CONSOLE) {
2850 sc->font_8 = font_8;
2851 sc->font_14 = font_14;
2852 sc->font_16 = font_16;
2853 } else if (sc->font_8 == NULL) {
2854 /* assert(sc_malloc) */
2855 sc->font_8 = kmalloc(sizeof(font_8), M_SYSCONS, M_WAITOK);
2856 sc->font_14 = kmalloc(sizeof(font_14), M_SYSCONS, M_WAITOK);
2857 sc->font_16 = kmalloc(sizeof(font_16), M_SYSCONS, M_WAITOK);
2859 #endif
2861 lwkt_gettoken(&tty_token);
2862 /* extract the hardware cursor location and hide the cursor for now */
2863 (*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
2864 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
2865 lwkt_reltoken(&tty_token);
2867 /* set up the first console */
2868 sc->first_vty = unit*MAXCONS;
2869 sc->vtys = MAXCONS; /* XXX: should be configurable */
2870 if (flags & SC_KERNEL_CONSOLE) {
2871 scp = &main_console;
2872 sc->console_scp = scp;
2873 init_scp(sc, sc->first_vty, scp);
2874 sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
2875 (void *)sc_buffer, FALSE);
2876 if (sc_init_emulator(scp, SC_DFLT_TERM))
2877 sc_init_emulator(scp, "*");
2878 (*scp->tsw->te_default_attr)(scp,
2879 kernel_default.std_color,
2880 kernel_default.rev_color);
2881 } else {
2882 /* assert(sc_malloc) */
2883 sc->dev = kmalloc(sizeof(cdev_t)*sc->vtys, M_SYSCONS, M_WAITOK | M_ZERO);
2885 sc->dev[0] = make_dev(&sc_ops, unit*MAXCONS, UID_ROOT,
2886 GID_WHEEL, 0600, "ttyv%r", unit*MAXCONS);
2888 sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
2889 scp = alloc_scp(sc, sc->first_vty);
2890 sc->dev[0]->si_drv1 = scp;
2892 sc->cur_scp = scp;
2894 /* copy screen to temporary buffer */
2895 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2896 (void *)scp->sc->adp->va_window, FALSE);
2897 if (ISTEXTSC(scp))
2898 sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
2900 /* move cursors to the initial positions */
2901 if (col >= scp->xsize)
2902 col = 0;
2903 if (row >= scp->ysize)
2904 row = scp->ysize - 1;
2905 scp->xpos = col;
2906 scp->ypos = row;
2907 scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
2908 if (bios_value.cursor_end < scp->font_height)
2909 sc->cursor_base = scp->font_height - bios_value.cursor_end - 1;
2910 else
2911 sc->cursor_base = 0;
2912 i = bios_value.cursor_end - bios_value.cursor_start + 1;
2913 sc->cursor_height = imin(i, scp->font_height);
2914 #ifndef SC_NO_SYSMOUSE
2915 sc_mouse_move(scp, scp->xpixel/2, scp->ypixel/2);
2916 #endif
2917 if (!ISGRAPHSC(scp)) {
2918 sc_set_cursor_image(scp);
2919 sc_draw_cursor_image(scp);
2922 /* save font and palette */
2923 #ifndef SC_NO_FONT_LOADING
2924 sc->fonts_loaded = 0;
2925 if (ISFONTAVAIL(sc->adp->va_flags)) {
2926 #ifdef SC_DFLT_FONT
2927 bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
2928 bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
2929 bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
2930 sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
2931 if (scp->font_height < 14) {
2932 sc_load_font(scp, 0, 8, sc->font_8, 0, 256);
2933 } else if (scp->font_height >= 16) {
2934 sc_load_font(scp, 0, 16, sc->font_16, 0, 256);
2935 } else {
2936 sc_load_font(scp, 0, 14, sc->font_14, 0, 256);
2938 #else /* !SC_DFLT_FONT */
2939 if (scp->font_height < 14) {
2940 sc_save_font(scp, 0, 8, sc->font_8, 0, 256);
2941 sc->fonts_loaded = FONT_8;
2942 } else if (scp->font_height >= 16) {
2943 sc_save_font(scp, 0, 16, sc->font_16, 0, 256);
2944 sc->fonts_loaded = FONT_16;
2945 } else {
2946 sc_save_font(scp, 0, 14, sc->font_14, 0, 256);
2947 sc->fonts_loaded = FONT_14;
2949 #endif /* SC_DFLT_FONT */
2950 /* FONT KLUDGE: always use the font page #0. XXX */
2951 sc_show_font(scp, 0);
2953 #endif /* !SC_NO_FONT_LOADING */
2955 #ifndef SC_NO_PALETTE_LOADING
2956 save_palette(sc->adp, sc->palette);
2957 #endif
2959 #if NSPLASH > 0
2960 if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
2961 /* we are ready to put up the splash image! */
2962 splash_init(sc->adp, scsplash_callback, sc);
2963 sc->flags |= SC_SPLASH_SCRN;
2965 #endif /* NSPLASH */
2968 /* the rest is not necessary, if we have done it once */
2969 if (sc->flags & SC_INIT_DONE) {
2970 return;
2973 /* initialize mapscrn arrays to a one to one map */
2974 for (i = 0; i < sizeof(sc->scr_map); i++)
2975 sc->scr_map[i] = sc->scr_rmap[i] = i;
2977 sc->flags |= SC_INIT_DONE;
2980 static void
2981 scterm(int unit, int flags)
2983 sc_softc_t *sc;
2984 scr_stat *scp;
2986 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
2987 if (sc == NULL)
2988 return; /* shouldn't happen */
2990 lwkt_gettoken(&tty_token);
2991 #if NSPLASH > 0
2992 /* this console is no longer available for the splash screen */
2993 if (sc->flags & SC_SPLASH_SCRN) {
2994 splash_term(sc->adp);
2995 sc->flags &= ~SC_SPLASH_SCRN;
2997 #endif /* NSPLASH */
2999 #if 0 /* XXX */
3000 /* move the hardware cursor to the upper-left corner */
3001 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
3002 #endif
3004 /* release the keyboard and the video card */
3005 if (sc->keyboard >= 0)
3006 kbd_release(sc->kbd, &sc->keyboard);
3007 if (sc->adapter >= 0)
3008 vid_release(sc->adp, &sc->adapter);
3011 * Stop the terminal emulator, if any. If operating on the
3012 * kernel console sc->dev may not be setup yet.
3014 if (flags & SC_KERNEL_CONSOLE)
3015 scp = sc->console_scp;
3016 else
3017 scp = SC_STAT(sc->dev[0]);
3018 if (scp->tsw)
3019 (*scp->tsw->te_term)(scp, &scp->ts);
3020 if (scp->ts != NULL)
3021 kfree(scp->ts, M_SYSCONS);
3023 /* clear the structure */
3024 if (!(flags & SC_KERNEL_CONSOLE)) {
3025 /* XXX: We need delete_dev() for this */
3026 kfree(sc->dev, M_SYSCONS);
3027 #if 0
3028 /* XXX: We need a ttyunregister for this */
3029 kfree(sc->tty, M_SYSCONS);
3030 #endif
3031 #ifndef SC_NO_FONT_LOADING
3032 kfree(sc->font_8, M_SYSCONS);
3033 kfree(sc->font_14, M_SYSCONS);
3034 kfree(sc->font_16, M_SYSCONS);
3035 #endif
3036 /* XXX vtb, history */
3038 bzero(sc, sizeof(*sc));
3039 sc->keyboard = -1;
3040 sc->adapter = -1;
3041 lwkt_reltoken(&tty_token);
3044 static void
3045 scshutdown(void *arg, int howto)
3047 /* assert(sc_console != NULL) */
3049 lwkt_gettoken(&tty_token);
3050 syscons_lock();
3051 sc_touch_scrn_saver();
3052 if (!cold && sc_console
3053 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
3054 && sc_console->smode.mode == VT_AUTO) {
3055 sc_switch_scr(sc_console->sc, sc_console->index);
3057 shutdown_in_progress = TRUE;
3058 syscons_unlock();
3059 lwkt_reltoken(&tty_token);
3063 sc_clean_up(scr_stat *scp)
3065 #if NSPLASH > 0
3066 int error;
3067 #endif /* NSPLASH */
3069 lwkt_gettoken(&tty_token);
3070 if (scp->sc->flags & SC_SCRN_BLANKED) {
3071 sc_touch_scrn_saver();
3072 #if NSPLASH > 0
3073 if ((error = wait_scrn_saver_stop(scp->sc))) {
3074 lwkt_reltoken(&tty_token);
3075 return error;
3077 #endif /* NSPLASH */
3079 scp->status |= MOUSE_HIDDEN;
3080 sc_remove_mouse_image(scp);
3081 sc_remove_cutmarking(scp);
3082 lwkt_reltoken(&tty_token);
3083 return 0;
3086 void
3087 sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
3089 sc_vtb_t new;
3090 sc_vtb_t old;
3092 lwkt_gettoken(&tty_token);
3093 old = scp->vtb;
3094 sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
3095 if (!discard && (old.vtb_flags & VTB_VALID)) {
3096 /* retain the current cursor position and buffer contants */
3097 scp->cursor_oldpos = scp->cursor_pos;
3099 * This works only if the old buffer has the same size as or larger
3100 * than the new one. XXX
3102 sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
3103 scp->vtb = new;
3104 } else {
3105 scp->vtb = new;
3106 sc_vtb_destroy(&old);
3109 #ifndef SC_NO_SYSMOUSE
3110 /* move the mouse cursor at the center of the screen */
3111 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
3112 #endif
3113 lwkt_reltoken(&tty_token);
3116 static scr_stat *
3117 alloc_scp(sc_softc_t *sc, int vty)
3119 scr_stat *scp;
3121 /* assert(sc_malloc) */
3123 scp = kmalloc(sizeof(scr_stat), M_SYSCONS, M_WAITOK);
3124 init_scp(sc, vty, scp);
3126 sc_alloc_scr_buffer(scp, TRUE, TRUE);
3127 if (sc_init_emulator(scp, SC_DFLT_TERM))
3128 sc_init_emulator(scp, "*");
3130 #ifndef SC_NO_CUTPASTE
3131 sc_alloc_cut_buffer(scp, TRUE);
3132 #endif
3134 #ifndef SC_NO_HISTORY
3135 sc_alloc_history_buffer(scp, 0, 0, TRUE);
3136 #endif
3137 return scp;
3141 * NOTE: Must be called with tty_token held.
3143 static void
3144 init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
3146 video_info_t info;
3147 int scaled_font_height;
3149 bzero(scp, sizeof(*scp));
3151 scp->index = vty;
3152 scp->sc = sc;
3153 scp->status = 0;
3154 scp->mode = sc->initial_mode;
3155 callout_init_mp(&scp->blink_screen_ch);
3156 lwkt_gettoken(&tty_token);
3157 (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
3158 lwkt_reltoken(&tty_token);
3159 if (info.vi_flags & V_INFO_GRAPHICS) {
3160 scp->status |= GRAPHICS_MODE;
3161 scp->xpixel = info.vi_width;
3162 scp->ypixel = info.vi_height;
3163 scp->xsize = info.vi_width/8;
3164 scp->ysize = info.vi_height/info.vi_cheight;
3165 scp->font_height = 0;
3166 scp->font_width = 0;
3167 scp->font = NULL;
3168 } else {
3169 scp->xsize = info.vi_width;
3170 scp->ysize = info.vi_height;
3171 scp->xpixel = scp->xsize*8;
3172 scp->ypixel = scp->ysize*info.vi_cheight;
3173 scp->font_width = 8;
3174 if (info.vi_cheight < 14) {
3175 scp->font_height = 8;
3176 #ifndef SC_NO_FONT_LOADING
3177 scp->font = sc->font_8;
3178 #else
3179 scp->font = NULL;
3180 #endif
3181 } else if (info.vi_cheight >= 16) {
3182 scp->font_height = 16;
3183 #ifndef SC_NO_FONT_LOADING
3184 scp->font = sc->font_16;
3185 #else
3186 scp->font = NULL;
3187 #endif
3188 } else {
3189 scp->font_height = 14;
3190 #ifndef SC_NO_FONT_LOADING
3191 scp->font = sc->font_14;
3192 #else
3193 scp->font = NULL;
3194 #endif
3197 scp->xoff = scp->yoff = 0;
3198 scp->xpos = scp->ypos = 0;
3199 scp->fbi = sc->fbi;
3200 if (scp->fbi != NULL) {
3201 scp->xpixel = scp->fbi->width;
3202 scp->ypixel = scp->fbi->height;
3204 scp->blk_width = scp->xpixel / 80;
3205 scaled_font_height = scp->blk_width * 100 / scp->font_width;
3206 scp->blk_height = scp->ypixel * 100 / scaled_font_height;
3208 scp->xsize = scp->xpixel / scp->blk_width;
3209 scp->ysize = scp->ypixel / scp->blk_height;
3210 scp->xpad = scp->fbi->stride / 4 - scp->xsize * scp->blk_width;
3212 sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
3213 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
3214 scp->start = scp->xsize * scp->ysize - 1;
3215 scp->end = 0;
3216 scp->tsw = NULL;
3217 scp->ts = NULL;
3218 scp->rndr = NULL;
3219 scp->border = BG_BLACK;
3220 scp->cursor_base = sc->cursor_base;
3221 scp->cursor_height = imin(sc->cursor_height, scp->font_height);
3222 scp->mouse_cut_start = scp->xsize * scp->ysize;
3223 scp->mouse_cut_end = -1;
3224 scp->mouse_signal = 0;
3225 scp->mouse_pid = 0;
3226 scp->mouse_proc = NULL;
3227 scp->kbd_mode = K_XLATE;
3228 scp->bell_pitch = bios_value.bell_pitch;
3229 scp->bell_duration = BELL_DURATION;
3230 scp->status |= (bios_value.shift_state & NLKED);
3231 scp->status |= CURSOR_ENABLED | MOUSE_HIDDEN;
3232 scp->pid = 0;
3233 scp->proc = NULL;
3234 scp->smode.mode = VT_AUTO;
3235 scp->history = NULL;
3236 scp->history_pos = 0;
3237 scp->history_size = 0;
3241 sc_init_emulator(scr_stat *scp, char *name)
3243 sc_term_sw_t *sw;
3244 sc_rndr_sw_t *rndr;
3245 void *p;
3246 int error;
3248 if (name == NULL) /* if no name is given, use the current emulator */
3249 sw = scp->tsw;
3250 else /* ...otherwise find the named emulator */
3251 sw = sc_term_match(name);
3252 if (sw == NULL) {
3253 return EINVAL;
3256 rndr = NULL;
3257 if (strcmp(sw->te_renderer, "*") != 0) {
3258 rndr = sc_render_match(scp, sw->te_renderer, scp->model);
3260 if (rndr == NULL && scp->sc->fbi != NULL) {
3261 rndr = sc_render_match(scp, "kms", scp->model);
3263 if (rndr == NULL) {
3264 rndr = sc_render_match(scp, scp->sc->adp->va_name, scp->model);
3265 if (rndr == NULL) {
3266 return ENODEV;
3270 if (sw == scp->tsw) {
3271 error = (*sw->te_init)(scp, &scp->ts, SC_TE_WARM_INIT);
3272 scp->rndr = rndr;
3273 sc_clear_screen(scp);
3274 /* assert(error == 0); */
3275 return error;
3278 if (sc_malloc && (sw->te_size > 0))
3279 p = kmalloc(sw->te_size, M_SYSCONS, M_NOWAIT);
3280 else
3281 p = NULL;
3282 error = (*sw->te_init)(scp, &p, SC_TE_COLD_INIT);
3283 if (error) {
3284 return error;
3287 if (scp->tsw)
3288 (*scp->tsw->te_term)(scp, &scp->ts);
3289 if (scp->ts != NULL)
3290 kfree(scp->ts, M_SYSCONS);
3291 scp->tsw = sw;
3292 scp->ts = p;
3293 scp->rndr = rndr;
3295 /* XXX */
3296 (*sw->te_default_attr)(scp, user_default.std_color, user_default.rev_color);
3297 sc_clear_screen(scp);
3299 return 0;
3303 * scgetc(flags) - get character from keyboard.
3304 * If flags & SCGETC_CN, then avoid harmful side effects.
3305 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3306 * return NOKEY if there is nothing there.
3308 static u_int
3309 scgetc(sc_softc_t *sc, u_int flags)
3311 scr_stat *scp;
3312 #ifndef SC_NO_HISTORY
3313 struct tty *tp;
3314 #endif
3315 u_int c;
3316 int this_scr;
3317 int f;
3318 int i;
3320 lwkt_gettoken(&tty_token);
3321 if (sc->kbd == NULL) {
3322 lwkt_reltoken(&tty_token);
3323 return NOKEY;
3326 next_code:
3327 #if 1
3328 /* I don't like this, but... XXX */
3329 if (flags & SCGETC_CN) {
3330 syscons_lock();
3331 sccnupdate(sc->cur_scp);
3332 syscons_unlock();
3334 #endif
3335 scp = sc->cur_scp;
3336 /* first see if there is something in the keyboard port */
3337 for (;;) {
3338 c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
3339 if (c == ERRKEY) {
3340 if (!(flags & SCGETC_CN))
3341 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3342 } else if (c == NOKEY) {
3343 lwkt_reltoken(&tty_token);
3344 return c;
3345 } else {
3346 break;
3350 /* make screensaver happy */
3351 if (!(c & RELKEY))
3352 sc_touch_scrn_saver();
3354 if (!(flags & SCGETC_CN))
3355 /* do the /dev/random device a favour */
3356 add_keyboard_randomness(c);
3358 if (scp->kbd_mode != K_XLATE) {
3359 lwkt_reltoken(&tty_token);
3360 return KEYCHAR(c);
3363 /* if scroll-lock pressed allow history browsing */
3364 if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
3366 scp->status &= ~CURSOR_ENABLED;
3367 sc_remove_cursor_image(scp);
3369 #ifndef SC_NO_HISTORY
3370 if (!(scp->status & BUFFER_SAVED)) {
3371 scp->status |= BUFFER_SAVED;
3372 sc_hist_save(scp);
3374 switch (c) {
3375 /* FIXME: key codes */
3376 case SPCLKEY | FKEY | F(49): /* home key */
3377 sc_remove_cutmarking(scp);
3378 sc_hist_home(scp);
3379 goto next_code;
3381 case SPCLKEY | FKEY | F(57): /* end key */
3382 sc_remove_cutmarking(scp);
3383 sc_hist_end(scp);
3384 goto next_code;
3386 case SPCLKEY | FKEY | F(50): /* up arrow key */
3387 sc_remove_cutmarking(scp);
3388 if (sc_hist_up_line(scp))
3389 if (!(flags & SCGETC_CN))
3390 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3391 goto next_code;
3393 case SPCLKEY | FKEY | F(58): /* down arrow key */
3394 sc_remove_cutmarking(scp);
3395 if (sc_hist_down_line(scp))
3396 if (!(flags & SCGETC_CN))
3397 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3398 goto next_code;
3400 case SPCLKEY | FKEY | F(51): /* page up key */
3401 sc_remove_cutmarking(scp);
3402 for (i=0; i<scp->ysize; i++) {
3403 if (sc_hist_up_line(scp)) {
3404 if (!(flags & SCGETC_CN))
3405 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3406 break;
3409 goto next_code;
3411 case SPCLKEY | FKEY | F(59): /* page down key */
3412 sc_remove_cutmarking(scp);
3413 for (i=0; i<scp->ysize; i++) {
3414 if (sc_hist_down_line(scp)) {
3415 if (!(flags & SCGETC_CN))
3416 sc_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3417 break;
3420 goto next_code;
3422 #endif /* SC_NO_HISTORY */
3426 * Process and consume special keys here. Return a plain char code
3427 * or a char code with the META flag or a function key code.
3429 if (c & RELKEY) {
3430 /* key released */
3431 /* goto next_code */
3432 } else {
3433 /* key pressed */
3434 if (c & SPCLKEY) {
3435 c &= ~SPCLKEY;
3436 switch (KEYCHAR(c)) {
3437 /* LOCKING KEYS */
3438 case NLK: case CLK: case ALK:
3439 break;
3440 case SLK:
3441 kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3442 if (f & SLKED) {
3443 scp->status |= SLKED;
3444 } else {
3445 if (scp->status & SLKED) {
3446 scp->status &= ~SLKED;
3447 #ifndef SC_NO_HISTORY
3448 if (scp->status & BUFFER_SAVED) {
3449 if (!sc_hist_restore(scp))
3450 sc_remove_cutmarking(scp);
3451 scp->status &= ~BUFFER_SAVED;
3452 scp->status |= CURSOR_ENABLED;
3453 sc_draw_cursor_image(scp);
3455 tp = VIRTUAL_TTY(sc, scp->index);
3456 if (ISTTYOPEN(tp))
3457 scstart(tp);
3458 #endif
3461 break;
3463 /* NON-LOCKING KEYS */
3464 case NOP:
3465 case LSH: case RSH: case LCTR: case RCTR:
3466 case LALT: case RALT: case ASH: case META:
3467 break;
3469 case BTAB:
3470 if (!(sc->flags & SC_SCRN_BLANKED)) {
3471 lwkt_reltoken(&tty_token);
3472 return c;
3474 break;
3476 case SPSC:
3477 #if NSPLASH > 0
3478 /* force activatation/deactivation of the screen saver */
3479 if (!(sc->flags & SC_SCRN_BLANKED)) {
3480 run_scrn_saver = TRUE;
3481 sc->scrn_time_stamp -= scrn_blank_time;
3483 if (cold) {
3485 * While devices are being probed, the screen saver need
3486 * to be invoked explictly. XXX
3488 if (sc->flags & SC_SCRN_BLANKED) {
3489 scsplash_stick(FALSE);
3490 stop_scrn_saver(sc, current_saver);
3491 } else {
3492 if (!ISGRAPHSC(scp)) {
3493 scsplash_stick(TRUE);
3494 (*current_saver)(sc, TRUE);
3498 #endif /* NSPLASH */
3499 break;
3501 case RBT:
3502 #ifndef SC_DISABLE_REBOOT
3503 shutdown_nice(0);
3504 #endif
3505 break;
3507 case HALT:
3508 #ifndef SC_DISABLE_REBOOT
3509 shutdown_nice(RB_HALT);
3510 #endif
3511 break;
3513 case PDWN:
3514 #ifndef SC_DISABLE_REBOOT
3515 shutdown_nice(RB_HALT|RB_POWEROFF);
3516 #endif
3517 break;
3519 #if __i386__ && NAPM > 0
3520 case SUSP:
3521 apm_suspend(PMST_SUSPEND);
3522 break;
3523 case STBY:
3524 apm_suspend(PMST_STANDBY);
3525 break;
3526 #else
3527 case SUSP:
3528 case STBY:
3529 break;
3530 #endif
3532 case DBG:
3533 #ifndef SC_DISABLE_DDBKEY
3534 #ifdef DDB
3535 lwkt_reltoken(&tty_token);
3536 Debugger("manual escape to debugger");
3537 lwkt_gettoken(&tty_token);
3538 #else
3539 kprintf("No debugger in kernel\n");
3540 #endif
3541 #else /* SC_DISABLE_DDBKEY */
3542 /* do nothing */
3543 #endif /* SC_DISABLE_DDBKEY */
3544 break;
3546 case PNC:
3547 if (enable_panic_key)
3548 panic("Forced by the panic key");
3549 break;
3551 case NEXT:
3552 this_scr = scp->index;
3553 for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3554 sc->first_vty + i != this_scr;
3555 i = (i + 1)%sc->vtys) {
3556 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3557 if (ISTTYOPEN(tp)) {
3558 syscons_lock();
3559 sc_switch_scr(scp->sc, sc->first_vty + i);
3560 syscons_unlock();
3561 break;
3564 break;
3566 case PREV:
3567 this_scr = scp->index;
3568 for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3569 sc->first_vty + i != this_scr;
3570 i = (i + sc->vtys - 1)%sc->vtys) {
3571 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3572 if (ISTTYOPEN(tp)) {
3573 syscons_lock();
3574 sc_switch_scr(scp->sc, sc->first_vty + i);
3575 syscons_unlock();
3576 break;
3579 break;
3581 default:
3582 if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3583 syscons_lock();
3584 sc_switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3585 syscons_unlock();
3586 break;
3588 /* assert(c & FKEY) */
3589 if (!(sc->flags & SC_SCRN_BLANKED)) {
3590 lwkt_reltoken(&tty_token);
3591 return c;
3593 break;
3595 /* goto next_code */
3596 } else {
3597 /* regular keys (maybe MKEY is set) */
3598 if (!(sc->flags & SC_SCRN_BLANKED)) {
3599 lwkt_reltoken(&tty_token);
3600 return c;
3605 goto next_code;
3609 scmmap(struct dev_mmap_args *ap)
3611 scr_stat *scp;
3613 lwkt_gettoken(&tty_token);
3614 scp = SC_STAT(ap->a_head.a_dev);
3615 if (scp != scp->sc->cur_scp) {
3616 lwkt_reltoken(&tty_token);
3617 return EINVAL;
3619 ap->a_result = (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, ap->a_offset,
3620 ap->a_nprot);
3621 lwkt_reltoken(&tty_token);
3622 return(0);
3625 static int
3626 save_kbd_state(scr_stat *scp, int unlock)
3628 int state;
3629 int error;
3631 WANT_UNLOCK(unlock);
3632 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3633 WANT_LOCK(unlock);
3635 if (error == ENOIOCTL)
3636 error = ENODEV;
3637 if (error == 0) {
3638 scp->status &= ~LOCK_MASK;
3639 scp->status |= state;
3641 return error;
3644 static int
3645 update_kbd_state(scr_stat *scp, int new_bits, int mask, int unlock)
3647 int state;
3648 int error;
3650 if (mask != LOCK_MASK) {
3651 WANT_UNLOCK(unlock);
3652 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3653 WANT_LOCK(unlock);
3655 if (error == ENOIOCTL)
3656 error = ENODEV;
3657 if (error) {
3658 return error;
3660 state &= ~mask;
3661 state |= new_bits & mask;
3662 } else {
3663 state = new_bits & LOCK_MASK;
3665 WANT_UNLOCK(unlock);
3666 error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3667 WANT_LOCK(unlock);
3668 if (error == ENOIOCTL)
3669 error = ENODEV;
3670 return error;
3673 static int
3674 update_kbd_leds(scr_stat *scp, int which)
3676 int error;
3678 which &= LOCK_MASK;
3679 error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3680 if (error == ENOIOCTL)
3681 error = ENODEV;
3682 return error;
3686 set_mode(scr_stat *scp)
3688 video_info_t info;
3690 lwkt_gettoken(&tty_token);
3691 /* reject unsupported mode */
3692 if (scp->sc->fbi == NULL && (*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info)) {
3693 lwkt_reltoken(&tty_token);
3694 return 1;
3697 /* if this vty is not currently showing, do nothing */
3698 if (scp != scp->sc->cur_scp) {
3699 lwkt_reltoken(&tty_token);
3700 return 0;
3703 /* setup video hardware for the given mode */
3704 if (scp->sc->fbi == NULL)
3705 (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3706 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3707 (void *)scp->sc->adp->va_window, FALSE);
3708 if (scp->sc->fbi != NULL)
3709 goto done;
3711 #ifndef SC_NO_FONT_LOADING
3712 /* load appropriate font */
3713 if (!(scp->status & GRAPHICS_MODE)) {
3714 if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3715 if (scp->font_height < 14) {
3716 if (scp->sc->fonts_loaded & FONT_8)
3717 sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256);
3718 } else if (scp->font_height >= 16) {
3719 if (scp->sc->fonts_loaded & FONT_16)
3720 sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256);
3721 } else {
3722 if (scp->sc->fonts_loaded & FONT_14)
3723 sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256);
3726 * FONT KLUDGE:
3727 * This is an interim kludge to display correct font.
3728 * Always use the font page #0 on the video plane 2.
3729 * Somehow we cannot show the font in other font pages on
3730 * some video cards... XXX
3732 sc_show_font(scp, 0);
3734 mark_all(scp);
3736 #endif /* !SC_NO_FONT_LOADING */
3738 sc_set_border(scp, scp->border);
3739 sc_set_cursor_image(scp);
3741 done:
3742 lwkt_reltoken(&tty_token);
3743 return 0;
3746 void
3747 refresh_ega_palette(scr_stat *scp)
3749 uint32_t r, g, b;
3750 int reg;
3751 int rsize, gsize, bsize;
3752 int rfld, gfld, bfld;
3753 int i;
3755 rsize = scp->sc->adp->va_info.vi_pixel_fsizes[0];
3756 gsize = scp->sc->adp->va_info.vi_pixel_fsizes[1];
3757 bsize = scp->sc->adp->va_info.vi_pixel_fsizes[2];
3758 rfld = scp->sc->adp->va_info.vi_pixel_fields[0];
3759 gfld = scp->sc->adp->va_info.vi_pixel_fields[1];
3760 bfld = scp->sc->adp->va_info.vi_pixel_fields[2];
3762 for (i = 0; i < 16; i++) {
3763 reg = scp->sc->adp->va_palette_regs[i];
3765 r = scp->sc->palette[reg * 3] >> (8 - rsize);
3766 g = scp->sc->palette[reg * 3 + 1] >> (8 - gsize);
3767 b = scp->sc->palette[reg * 3 + 2] >> (8 - bsize);
3769 scp->ega_palette[i] = (r << rfld) + (g << gfld) + (b << bfld);
3773 void
3774 sc_set_border(scr_stat *scp, int color)
3776 ++scp->sc->videoio_in_progress;
3777 (*scp->rndr->draw_border)(scp, color);
3778 --scp->sc->videoio_in_progress;
3781 #ifndef SC_NO_FONT_LOADING
3782 void
3783 sc_load_font(scr_stat *scp, int page, int size, u_char *buf,
3784 int base, int count)
3786 sc_softc_t *sc;
3788 sc = scp->sc;
3789 sc->font_loading_in_progress = TRUE;
3790 (*vidsw[sc->adapter]->load_font)(sc->adp, page, size, buf, base, count);
3791 sc->font_loading_in_progress = FALSE;
3794 void
3795 sc_save_font(scr_stat *scp, int page, int size, u_char *buf,
3796 int base, int count)
3798 sc_softc_t *sc;
3800 sc = scp->sc;
3801 sc->font_loading_in_progress = TRUE;
3802 (*vidsw[sc->adapter]->save_font)(sc->adp, page, size, buf, base, count);
3803 sc->font_loading_in_progress = FALSE;
3806 void
3807 sc_show_font(scr_stat *scp, int page)
3809 (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, page);
3811 #endif /* !SC_NO_FONT_LOADING */
3813 void
3814 sc_paste(scr_stat *scp, u_char *p, int count)
3816 struct tty *tp;
3817 u_char *rmap;
3820 * Holy hell, don't try to inject a paste buffer if the keyboard
3821 * is not in ascii mode!
3823 if (scp->kbd_mode != K_XLATE)
3824 return;
3826 lwkt_gettoken(&tty_token);
3827 if (scp->status & MOUSE_VISIBLE) {
3828 tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
3829 if (!ISTTYOPEN(tp)) {
3830 lwkt_reltoken(&tty_token);
3831 return;
3833 rmap = scp->sc->scr_rmap;
3834 for (; count > 0; --count)
3835 (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
3837 lwkt_reltoken(&tty_token);
3840 void
3841 sc_bell(scr_stat *scp, int pitch, int duration)
3843 if (cold || shutdown_in_progress)
3844 return;
3846 if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL)) {
3847 return;
3850 if (scp->sc->flags & SC_VISUAL_BELL) {
3851 if (scp->sc->blink_in_progress) {
3852 return;
3854 scp->sc->blink_in_progress = 3;
3855 if (scp != scp->sc->cur_scp)
3856 scp->sc->blink_in_progress += 2;
3857 sc_blink_screen(scp->sc->cur_scp);
3858 } else if (duration != 0 && pitch != 0) {
3859 if (scp != scp->sc->cur_scp)
3860 pitch *= 2;
3861 sysbeep(pitch, duration);
3866 * Two versions of blink_screen(), one called from the console path
3867 * with the syscons locked, and one called from a timer callout.
3869 static void
3870 sc_blink_screen(scr_stat *scp)
3872 if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
3873 scp->sc->blink_in_progress = 0;
3874 mark_all(scp);
3875 if (scp->sc->delayed_next_scr)
3876 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3877 } else {
3878 (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
3879 scp->sc->blink_in_progress & 1);
3880 scp->sc->blink_in_progress--;
3884 #if 0
3885 static void
3886 blink_screen_callout(void *arg)
3888 scr_stat *scp = arg;
3889 struct tty *tp;
3891 if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
3892 syscons_lock();
3893 scp->sc->blink_in_progress = 0;
3894 mark_all(scp);
3895 syscons_unlock();
3896 tp = VIRTUAL_TTY(scp->sc, scp->index);
3897 if (ISTTYOPEN(tp))
3898 scstart(tp);
3899 if (scp->sc->delayed_next_scr) {
3900 syscons_lock();
3901 sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3902 syscons_unlock();
3904 } else {
3905 syscons_lock();
3906 (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
3907 scp->sc->blink_in_progress & 1);
3908 scp->sc->blink_in_progress--;
3909 syscons_unlock();
3910 callout_reset(&scp->blink_screen_ch, hz / 10,
3911 blink_screen_callout, scp);
3914 #endif
3917 * Allocate active keyboard. Try to allocate "kbdmux" keyboard first, and,
3918 * if found, add all non-busy keyboards to "kbdmux". Otherwise look for
3919 * any keyboard.
3922 static int
3923 sc_allocate_keyboard(sc_softc_t *sc, int unit)
3925 int idx0, idx;
3926 keyboard_t *k0, *k;
3927 keyboard_info_t ki;
3929 idx0 = kbd_allocate("kbdmux", -1, (void *)&sc->keyboard, sckbdevent, sc);
3930 if (idx0 != -1) {
3931 k0 = kbd_get_keyboard(idx0);
3933 for (idx = kbd_find_keyboard2("*", -1, 0, 0);
3934 idx != -1;
3935 idx = kbd_find_keyboard2("*", -1, idx + 1, 0)) {
3936 k = kbd_get_keyboard(idx);
3938 if (idx == idx0 || KBD_IS_BUSY(k))
3939 continue;
3941 bzero(&ki, sizeof(ki));
3942 strcpy(ki.kb_name, k->kb_name);
3943 ki.kb_unit = k->kb_unit;
3945 kbd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
3947 } else
3948 idx0 = kbd_allocate("*", unit, (void *)&sc->keyboard, sckbdevent, sc);
3950 return (idx0);