xref: /freebsd-14.2/sys/dev/syscons/syscons.c (revision 26fe698c)
1 /*-
2  * Copyright (c) 1992-1998 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include "sc.h"
32 #include "splash.h"
33 #include "opt_syscons.h"
34 #include "opt_ddb.h"
35 #ifdef __i386__
36 #include "apm.h"
37 #endif
38 
39 #if NSC > 0
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/eventhandler.h>
43 #include <sys/reboot.h>
44 #include <sys/conf.h>
45 #include <sys/proc.h>
46 #include <sys/signalvar.h>
47 #include <sys/tty.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/cons.h>
51 
52 #include <machine/clock.h>
53 #include <machine/console.h>
54 #include <machine/psl.h>
55 #include <machine/pc/display.h>
56 #ifdef __i386__
57 #include <machine/apm_bios.h>
58 #include <machine/frame.h>
59 #include <machine/random.h>
60 #endif
61 
62 #include <dev/kbd/kbdreg.h>
63 #include <dev/fb/fbreg.h>
64 #include <dev/fb/splashreg.h>
65 #include <dev/syscons/syscons.h>
66 
67 #define COLD 0
68 #define WARM 1
69 
70 #define DEFAULT_BLANKTIME	(5*60)		/* 5 minutes */
71 #define MAX_BLANKTIME		(7*24*60*60)	/* 7 days!? */
72 
73 #define KEYCODE_BS		0x0e		/* "<-- Backspace" key, XXX */
74 
75 static default_attr user_default = {
76     SC_NORM_ATTR << 8,
77     SC_NORM_REV_ATTR << 8,
78 };
79 
80 static default_attr kernel_default = {
81     SC_KERNEL_CONS_ATTR << 8,
82     SC_KERNEL_CONS_REV_ATTR << 8,
83 };
84 
85 static	int		sc_console_unit = -1;
86 static  scr_stat    	*sc_console;
87 static	struct tty	*sc_console_tty;
88 #ifndef SC_NO_SYSMOUSE
89 static	struct tty	*sc_mouse_tty;
90 #endif
91 static  term_stat   	kernel_console;
92 static  default_attr    *current_default;
93 
94 static  char        	init_done = COLD;
95 static  char		shutdown_in_progress = FALSE;
96 static	char		sc_malloc = FALSE;
97 
98 static	int		saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
99 static	int		run_scrn_saver = FALSE;	/* should run the saver? */
100 static	long        	scrn_blank_time = 0;    /* screen saver timeout value */
101 #if NSPLASH > 0
102 static	int     	scrn_blanked;		/* # of blanked screen */
103 static	int		sticky_splash = FALSE;
104 
105 static	void		none_saver(sc_softc_t *sc, int blank) { }
106 static	void		(*current_saver)(sc_softc_t *, int) = none_saver;
107 #endif
108 
109 #if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
110 #include "font.h"
111 #endif
112 
113 	d_ioctl_t	*sc_user_ioctl;
114 
115 static	bios_values_t	bios_value;
116 
117 #define SC_MOUSE 	128
118 #define SC_CONSOLECTL	255
119 
120 #define VIRTUAL_TTY(sc, x) (SC_DEV((sc), (x))->si_tty)
121 
122 #define debugger	FALSE
123 
124 #ifdef __i386__
125 #ifdef DDB
126 extern int		in_Debugger;
127 #undef debugger
128 #define debugger	in_Debugger
129 #endif /* DDB */
130 #endif /* __i386__ */
131 
132 /* prototypes */
133 static int scvidprobe(int unit, int flags, int cons);
134 static int sckbdprobe(int unit, int flags, int cons);
135 static void scmeminit(void *arg);
136 static int scdevtounit(dev_t dev);
137 static kbd_callback_func_t sckbdevent;
138 static int scparam(struct tty *tp, struct termios *t);
139 static void scstart(struct tty *tp);
140 static void scmousestart(struct tty *tp);
141 static void scinit(int unit, int flags);
142 #if __i386__
143 static void scterm(int unit, int flags);
144 #endif
145 static void scshutdown(void *arg, int howto);
146 static u_int scgetc(sc_softc_t *sc, u_int flags);
147 #define SCGETC_CN	1
148 #define SCGETC_NONBLOCK	2
149 static int sccngetch(int flags);
150 static void sccnupdate(scr_stat *scp);
151 static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
152 static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
153 static timeout_t scrn_timer;
154 static int and_region(int *s1, int *e1, int s2, int e2);
155 static void scrn_update(scr_stat *scp, int show_cursor);
156 
157 #if NSPLASH > 0
158 static int scsplash_callback(int event, void *arg);
159 static void scsplash_saver(sc_softc_t *sc, int show);
160 static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
161 static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
162 static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
163 static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
164 static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
165 static int wait_scrn_saver_stop(sc_softc_t *sc);
166 #define scsplash_stick(stick)		(sticky_splash = (stick))
167 #else /* !NSPLASH */
168 #define scsplash_stick(stick)
169 #endif /* NSPLASH */
170 
171 static int switch_scr(sc_softc_t *sc, u_int next_scr);
172 static int do_switch_scr(sc_softc_t *sc, int s);
173 static int vt_proc_alive(scr_stat *scp);
174 static int signal_vt_rel(scr_stat *scp);
175 static int signal_vt_acq(scr_stat *scp);
176 static void exchange_scr(sc_softc_t *sc);
177 static void scan_esc(scr_stat *scp, u_char c);
178 static void ansi_put(scr_stat *scp, u_char *buf, int len);
179 static void draw_cursor_image(scr_stat *scp);
180 static void remove_cursor_image(scr_stat *scp);
181 static void update_cursor_image(scr_stat *scp);
182 static void move_crsr(scr_stat *scp, int x, int y);
183 static int mask2attr(struct term_stat *term);
184 static int save_kbd_state(scr_stat *scp);
185 static int update_kbd_state(scr_stat *scp, int state, int mask);
186 static int update_kbd_leds(scr_stat *scp, int which);
187 static void do_bell(scr_stat *scp, int pitch, int duration);
188 static timeout_t blink_screen;
189 
190 #define	CDEV_MAJOR	12
191 
192 static cn_probe_t	sccnprobe;
193 static cn_init_t	sccninit;
194 static cn_getc_t	sccngetc;
195 static cn_checkc_t	sccncheckc;
196 static cn_putc_t	sccnputc;
197 static cn_term_t	sccnterm;
198 
199 #if __alpha__
200 void sccnattach(void);
201 #endif
202 
203 CONS_DRIVER(sc, sccnprobe, sccninit, sccnterm, sccngetc, sccncheckc, sccnputc);
204 
205 static	d_open_t	scopen;
206 static	d_close_t	scclose;
207 static	d_read_t	scread;
208 static	d_write_t	scwrite;
209 static	d_ioctl_t	scioctl;
210 static	d_mmap_t	scmmap;
211 
212 static struct cdevsw sc_cdevsw = {
213 	/* open */	scopen,
214 	/* close */	scclose,
215 	/* read */	scread,
216 	/* write */	scwrite,
217 	/* ioctl */	scioctl,
218 	/* poll */	ttypoll,
219 	/* mmap */	scmmap,
220 	/* strategy */	nostrategy,
221 	/* name */	"sc",
222 	/* maj */	CDEV_MAJOR,
223 	/* dump */	nodump,
224 	/* psize */	nopsize,
225 	/* flags */	D_TTY,
226 	/* bmaj */	-1
227 };
228 
229 int
230 sc_probe_unit(int unit, int flags)
231 {
232     if (!scvidprobe(unit, flags, FALSE)) {
233 	if (bootverbose)
234 	    printf("sc%d: no video adapter is found.\n", unit);
235 	return ENXIO;
236     }
237 
238     /* syscons will be attached even when there is no keyboard */
239     sckbdprobe(unit, flags, FALSE);
240 
241     return 0;
242 }
243 
244 /* probe video adapters, return TRUE if found */
245 static int
246 scvidprobe(int unit, int flags, int cons)
247 {
248     /*
249      * Access the video adapter driver through the back door!
250      * Video adapter drivers need to be configured before syscons.
251      * However, when syscons is being probed as the low-level console,
252      * they have not been initialized yet.  We force them to initialize
253      * themselves here. XXX
254      */
255     vid_configure(cons ? VIO_PROBE_ONLY : 0);
256 
257     return (vid_find_adapter("*", unit) >= 0);
258 }
259 
260 /* probe the keyboard, return TRUE if found */
261 static int
262 sckbdprobe(int unit, int flags, int cons)
263 {
264     /* access the keyboard driver through the backdoor! */
265     kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
266 
267     return (kbd_find_keyboard("*", unit) >= 0);
268 }
269 
270 static char
271 *adapter_name(video_adapter_t *adp)
272 {
273     static struct {
274 	int type;
275 	char *name[2];
276     } names[] = {
277 	{ KD_MONO,	{ "MDA",	"MDA" } },
278 	{ KD_HERCULES,	{ "Hercules",	"Hercules" } },
279 	{ KD_CGA,	{ "CGA",	"CGA" } },
280 	{ KD_EGA,	{ "EGA",	"EGA (mono)" } },
281 	{ KD_VGA,	{ "VGA",	"VGA (mono)" } },
282 	{ KD_PC98,	{ "PC-98x1",	"PC-98x1" } },
283 	{ KD_TGA,	{ "TGA",	"TGA" } },
284 	{ -1,		{ "Unknown",	"Unknown" } },
285     };
286     int i;
287 
288     for (i = 0; names[i].type != -1; ++i)
289 	if (names[i].type == adp->va_type)
290 	    break;
291     return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
292 }
293 
294 int
295 sc_attach_unit(int unit, int flags)
296 {
297     sc_softc_t *sc;
298     scr_stat *scp;
299 #ifdef SC_PIXEL_MODE
300     video_info_t info;
301 #endif
302     int vc;
303     dev_t dev;
304 
305     scmeminit(NULL);		/* XXX */
306 
307     flags &= ~SC_KERNEL_CONSOLE;
308     if (sc_console_unit == unit)
309 	flags |= SC_KERNEL_CONSOLE;
310     scinit(unit, flags);
311     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
312     sc->config = flags;
313     scp = SC_STAT(sc->dev[0]);
314     if (sc_console == NULL)	/* sc_console_unit < 0 */
315 	sc_console = scp;
316 
317 #ifdef SC_PIXEL_MODE
318     if ((sc->config & SC_VESA800X600)
319 	&& ((*vidsw[sc->adapter]->get_info)(sc->adp, M_VESA_800x600, &info) == 0)) {
320 #if NSPLASH > 0
321 	if (sc->flags & SC_SPLASH_SCRN)
322 	    splash_term(sc->adp);
323 #endif
324 	sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
325 	sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
326 	sc->initial_mode = M_VESA_800x600;
327 #if NSPLASH > 0
328 	/* put up the splash again! */
329 	if (sc->flags & SC_SPLASH_SCRN)
330     	    splash_init(sc->adp, scsplash_callback, sc);
331 #endif
332     }
333 #endif /* SC_PIXEL_MODE */
334 
335     /* initialize cursor */
336     if (!ISGRAPHSC(scp))
337     	update_cursor_image(scp);
338 
339     /* get screen update going */
340     scrn_timer(sc);
341 
342     /* set up the keyboard */
343     kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
344     update_kbd_state(scp, scp->status, LOCK_MASK);
345 
346     printf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
347 	   unit, adapter_name(sc->adp), sc->vtys, sc->config);
348     if (bootverbose) {
349 	printf("sc%d:", unit);
350     	if (sc->adapter >= 0)
351 	    printf(" fb%d", sc->adapter);
352 	if (sc->keyboard >= 0)
353 	    printf(" kbd%d", sc->keyboard);
354 	printf("\n");
355     }
356 
357     /* register a shutdown callback for the kernel console */
358     if (sc_console_unit == unit)
359 	EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown,
360 			      (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
361 
362     /*
363      * syscons's cdevsw must be registered from here. As syscons and
364      * pcvt share the same major number, their cdevsw cannot be
365      * registered at module loading/initialization time or by SYSINIT.
366      */
367     cdevsw_add(&sc_cdevsw);	/* XXX do this just once... */
368 
369     for (vc = 0; vc < sc->vtys; vc++) {
370 	dev = make_dev(&sc_cdevsw, vc + unit * MAXCONS,
371 	    UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc + unit * MAXCONS);
372 	sc->dev[vc] = dev;
373 	/*
374 	 * The first vty already has struct tty and scr_stat initialized
375 	 * in scinit().  The other vtys will have these structs when
376 	 * first opened.
377 	 */
378     }
379 
380 #ifndef SC_NO_SYSMOUSE
381     dev = make_dev(&sc_cdevsw, SC_MOUSE,
382 		   UID_ROOT, GID_WHEEL, 0600, "sysmouse");
383     dev->si_tty = sc_mouse_tty = ttymalloc(sc_mouse_tty);
384     /* sysmouse doesn't have scr_stat */
385 #endif /* SC_NO_SYSMOUSE */
386     dev = make_dev(&sc_cdevsw, SC_CONSOLECTL,
387 		   UID_ROOT, GID_WHEEL, 0600, "consolectl");
388     dev->si_tty = sc_console_tty = ttymalloc(sc_console_tty);
389     SC_STAT(dev) = sc_console;
390 
391     return 0;
392 }
393 
394 static void
395 scmeminit(void *arg)
396 {
397     if (sc_malloc)
398 	return;
399     sc_malloc = TRUE;
400 
401     /*
402      * As soon as malloc() becomes functional, we had better allocate
403      * various buffers for the kernel console.
404      */
405 
406     if (sc_console_unit < 0)
407 	return;
408 
409     /* copy the temporary buffer to the final buffer */
410     sc_alloc_scr_buffer(sc_console, FALSE, FALSE);
411 
412 #ifndef SC_NO_CUTPASTE
413     /* cut buffer is available only when the mouse pointer is used */
414     if (ISMOUSEAVAIL(sc_console->sc->adp->va_flags))
415 	sc_alloc_cut_buffer(sc_console, FALSE);
416 #endif
417 
418 #ifndef SC_NO_HISTORY
419     /* initialize history buffer & pointers */
420     sc_alloc_history_buffer(sc_console, 0, 0, FALSE);
421 #endif
422 }
423 
424 /* XXX */
425 SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL);
426 
427 int
428 sc_resume_unit(int unit)
429 {
430     /* XXX should be moved to the keyboard driver? */
431     sc_softc_t *sc;
432 
433     sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
434     if (sc->kbd != NULL)
435 	kbd_clear_state(sc->kbd);
436     return 0;
437 }
438 
439 static int
440 scdevtounit(dev_t dev)
441 {
442     int vty = SC_VTY(dev);
443 
444     if (vty == SC_CONSOLECTL)
445 	return ((sc_console != NULL) ? sc_console->sc->unit : -1);
446     else if (vty == SC_MOUSE)
447 	return -1;
448     else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
449 	return -1;
450     else
451 	return vty/MAXCONS;
452 }
453 
454 int
455 scopen(dev_t dev, int flag, int mode, struct proc *p)
456 {
457     int unit = scdevtounit(dev);
458     sc_softc_t *sc;
459     struct tty *tp;
460     scr_stat *scp;
461     keyarg_t key;
462     int error;
463 
464     DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
465 		major(dev), minor(dev), unit, SC_VTY(dev)));
466 
467     /* sc == NULL, if SC_VTY(dev) == SC_MOUSE */
468     sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
469 #ifndef SC_NO_SYSMOUSE
470     if ((SC_VTY(dev) != SC_MOUSE) && (sc == NULL))
471 #else
472     if (sc == NULL)
473 #endif
474 	return ENXIO;
475 
476     tp = dev->si_tty = ttymalloc(dev->si_tty);
477     tp->t_oproc = (SC_VTY(dev) == SC_MOUSE) ? scmousestart : scstart;
478     tp->t_param = scparam;
479     tp->t_stop = nottystop;
480     tp->t_dev = dev;
481     if (!(tp->t_state & TS_ISOPEN)) {
482 	ttychars(tp);
483         /* Use the current setting of the <-- key as default VERASE. */
484         /* If the Delete key is preferable, an stty is necessary     */
485 	if (sc != NULL) {
486 	    key.keynum = KEYCODE_BS;
487 	    kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
488             tp->t_cc[VERASE] = key.key.map[0];
489 	}
490 	tp->t_iflag = TTYDEF_IFLAG;
491 	tp->t_oflag = TTYDEF_OFLAG;
492 	tp->t_cflag = TTYDEF_CFLAG;
493 	tp->t_lflag = TTYDEF_LFLAG;
494 	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
495 	scparam(tp, &tp->t_termios);
496 	(*linesw[tp->t_line].l_modem)(tp, 1);
497 #ifndef SC_NO_SYSMOUSE
498     	if (SC_VTY(dev) == SC_MOUSE)
499 	    sc_mouse_set_level(0);	/* XXX */
500 #endif
501     }
502     else
503 	if (tp->t_state & TS_XCLUDE && suser(p))
504 	    return(EBUSY);
505 
506     error = (*linesw[tp->t_line].l_open)(dev, tp);
507 
508     if (SC_VTY(dev) != SC_MOUSE) {
509 	/* assert(sc != NULL) */
510 	scp = SC_STAT(dev);
511 	if (scp == NULL) {
512 	    scp = SC_STAT(dev) = alloc_scp(sc, SC_VTY(dev));
513 	    if (ISGRAPHSC(scp))
514 		sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
515 	}
516 	if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
517 	    tp->t_winsize.ws_col = scp->xsize;
518 	    tp->t_winsize.ws_row = scp->ysize;
519 	}
520     }
521     return error;
522 }
523 
524 int
525 scclose(dev_t dev, int flag, int mode, struct proc *p)
526 {
527     struct tty *tp = dev->si_tty;
528     struct scr_stat *scp;
529     int s;
530 
531     if ((SC_VTY(dev) != SC_CONSOLECTL) && (SC_VTY(dev) != SC_MOUSE)) {
532 	scp = SC_STAT(tp->t_dev);
533 	/* were we in the middle of the VT switching process? */
534 	DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
535 	s = spltty();
536 	if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit))
537 	    cons_unavail = FALSE;
538 	if (scp->status & SWITCH_WAIT_REL) {
539 	    /* assert(scp == scp->sc->cur_scp) */
540 	    DPRINTF(5, ("reset WAIT_REL, "));
541 	    scp->status &= ~SWITCH_WAIT_REL;
542 	    do_switch_scr(scp->sc, s);
543 	}
544 	if (scp->status & SWITCH_WAIT_ACQ) {
545 	    /* assert(scp == scp->sc->cur_scp) */
546 	    DPRINTF(5, ("reset WAIT_ACQ, "));
547 	    scp->status &= ~SWITCH_WAIT_ACQ;
548 	    scp->sc->switch_in_progress = 0;
549 	}
550 #if not_yet_done
551 	if (scp == &main_console) {
552 	    scp->pid = 0;
553 	    scp->proc = NULL;
554 	    scp->smode.mode = VT_AUTO;
555 	}
556 	else {
557 	    sc_vtb_destroy(&scp->vtb);
558 	    sc_vtb_destroy(&scp->scr);
559 	    sc_free_history_buffer(scp, scp->ysize);
560 	    free(scp, M_DEVBUF);
561 	}
562 #else
563 	scp->pid = 0;
564 	scp->proc = NULL;
565 	scp->smode.mode = VT_AUTO;
566 #endif
567 	scp->kbd_mode = K_XLATE;
568 	if (scp == scp->sc->cur_scp)
569 	    kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
570 	DPRINTF(5, ("done.\n"));
571     }
572     spltty();
573     (*linesw[tp->t_line].l_close)(tp, flag);
574     ttyclose(tp);
575     spl0();
576     return(0);
577 }
578 
579 int
580 scread(dev_t dev, struct uio *uio, int flag)
581 {
582     struct tty *tp = dev->si_tty;
583 
584     sc_touch_scrn_saver();
585     return((*linesw[tp->t_line].l_read)(tp, uio, flag));
586 }
587 
588 int
589 scwrite(dev_t dev, struct uio *uio, int flag)
590 {
591     struct tty *tp = dev->si_tty;
592 
593     return((*linesw[tp->t_line].l_write)(tp, uio, flag));
594 }
595 
596 static int
597 sckbdevent(keyboard_t *thiskbd, int event, void *arg)
598 {
599     sc_softc_t *sc;
600     struct tty *cur_tty;
601     int c;
602     size_t len;
603     u_char *cp;
604 
605     sc = (sc_softc_t *)arg;
606     /* assert(thiskbd == sc->kbd) */
607 
608     switch (event) {
609     case KBDIO_KEYINPUT:
610 	break;
611     case KBDIO_UNLOADING:
612 	sc->kbd = NULL;
613 	sc->keyboard = -1;
614 	kbd_release(thiskbd, (void *)&sc->keyboard);
615 	return 0;
616     default:
617 	return EINVAL;
618     }
619 
620     /*
621      * Loop while there is still input to get from the keyboard.
622      * I don't think this is nessesary, and it doesn't fix
623      * the Xaccel-2.1 keyboard hang, but it can't hurt.		XXX
624      */
625     while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
626 
627 	cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
628 	/* XXX */
629 	if (!(cur_tty->t_state & TS_ISOPEN))
630 	    if (((cur_tty = sc_console_tty) == NULL)
631 	    	|| !(cur_tty->t_state & TS_ISOPEN))
632 		continue;
633 
634 	switch (KEYFLAGS(c)) {
635 	case 0x0000: /* normal key */
636 	    (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
637 	    break;
638 	case FKEY:  /* function key, return string */
639 	    cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
640 	    if (cp != NULL) {
641 	    	while (len-- >  0)
642 		    (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
643 	    }
644 	    break;
645 	case MKEY:  /* meta is active, prepend ESC */
646 	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
647 	    (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
648 	    break;
649 	case BKEY:  /* backtab fixed sequence (esc [ Z) */
650 	    (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
651 	    (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
652 	    (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
653 	    break;
654 	}
655     }
656 
657 #ifndef SC_NO_CUTPASTE
658     if (sc->cur_scp->status & MOUSE_VISIBLE) {
659 	sc_remove_mouse_image(sc->cur_scp);
660 	sc->cur_scp->status &= ~MOUSE_VISIBLE;
661     }
662 #endif /* SC_NO_CUTPASTE */
663 
664     return 0;
665 }
666 
667 static int
668 scparam(struct tty *tp, struct termios *t)
669 {
670     tp->t_ispeed = t->c_ispeed;
671     tp->t_ospeed = t->c_ospeed;
672     tp->t_cflag = t->c_cflag;
673     return 0;
674 }
675 
676 int
677 scioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
678 {
679     int error;
680     int i;
681     struct tty *tp;
682     sc_softc_t *sc;
683     scr_stat *scp;
684     int s;
685 
686     tp = dev->si_tty;
687 
688     /* If there is a user_ioctl function call that first */
689     if (sc_user_ioctl) {
690 	error = (*sc_user_ioctl)(dev, cmd, data, flag, p);
691 	if (error != ENOIOCTL)
692 	    return error;
693     }
694 
695     error = sc_vid_ioctl(tp, cmd, data, flag, p);
696     if (error != ENOIOCTL)
697 	return error;
698 
699 #ifndef SC_NO_HISTORY
700     error = sc_hist_ioctl(tp, cmd, data, flag, p);
701     if (error != ENOIOCTL)
702 	return error;
703 #endif
704 
705 #ifndef SC_NO_SYSMOUSE
706     error = sc_mouse_ioctl(tp, cmd, data, flag, p);
707     if (error != ENOIOCTL)
708 	return error;
709     if (SC_VTY(dev) == SC_MOUSE) {
710 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
711 	if (error != ENOIOCTL)
712 	    return error;
713 	error = ttioctl(tp, cmd, data, flag);
714 	if (error != ENOIOCTL)
715 	    return error;
716 	return ENOTTY;
717     }
718 #endif
719 
720     scp = SC_STAT(tp->t_dev);
721     /* assert(scp != NULL) */
722     /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
723     sc = scp->sc;
724 
725     switch (cmd) {  		/* process console hardware related ioctl's */
726 
727     case GIO_ATTR:      	/* get current attributes */
728 	*(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
729 	return 0;
730 
731     case GIO_COLOR:     	/* is this a color console ? */
732 	*(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
733 	return 0;
734 
735     case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
736 	if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
737             return EINVAL;
738 	s = spltty();
739 	scrn_blank_time = *(int *)data;
740 	run_scrn_saver = (scrn_blank_time != 0);
741 	splx(s);
742 	return 0;
743 
744     case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
745 	if (!ISGRAPHSC(sc->cur_scp))
746 	    remove_cursor_image(sc->cur_scp);
747 	if ((*(int*)data) & 0x01)
748 	    sc->flags |= SC_BLINK_CURSOR;
749 	else
750 	    sc->flags &= ~SC_BLINK_CURSOR;
751 	if ((*(int*)data) & 0x02) {
752 	    sc->flags |= SC_CHAR_CURSOR;
753 	} else
754 	    sc->flags &= ~SC_CHAR_CURSOR;
755 	/*
756 	 * The cursor shape is global property; all virtual consoles
757 	 * are affected. Update the cursor in the current console...
758 	 */
759 	if (!ISGRAPHSC(sc->cur_scp)) {
760 	    s = spltty();
761 	    sc_set_cursor_image(sc->cur_scp);
762 	    draw_cursor_image(sc->cur_scp);
763 	    splx(s);
764 	}
765 	return 0;
766 
767     case CONS_BELLTYPE: 	/* set bell type sound/visual */
768 	if ((*(int *)data) & 0x01)
769 	    sc->flags |= SC_VISUAL_BELL;
770 	else
771 	    sc->flags &= ~SC_VISUAL_BELL;
772 	if ((*(int *)data) & 0x02)
773 	    sc->flags |= SC_QUIET_BELL;
774 	else
775 	    sc->flags &= ~SC_QUIET_BELL;
776 	return 0;
777 
778     case CONS_GETINFO:  	/* get current (virtual) console info */
779     {
780 	vid_info_t *ptr = (vid_info_t*)data;
781 	if (ptr->size == sizeof(struct vid_info)) {
782 	    ptr->m_num = sc->cur_scp->index;
783 	    ptr->mv_col = scp->xpos;
784 	    ptr->mv_row = scp->ypos;
785 	    ptr->mv_csz = scp->xsize;
786 	    ptr->mv_rsz = scp->ysize;
787 	    ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
788 	    ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
789 	    ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
790 	    ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
791 	    ptr->mv_grfc.fore = 0;      /* not supported */
792 	    ptr->mv_grfc.back = 0;      /* not supported */
793 	    ptr->mv_ovscan = scp->border;
794 	    if (scp == sc->cur_scp)
795 		save_kbd_state(scp);
796 	    ptr->mk_keylock = scp->status & LOCK_MASK;
797 	    return 0;
798 	}
799 	return EINVAL;
800     }
801 
802     case CONS_GETVERS:  	/* get version number */
803 	*(int*)data = 0x200;    /* version 2.0 */
804 	return 0;
805 
806     case CONS_IDLE:		/* see if the screen has been idle */
807 	/*
808 	 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
809 	 * the user process may have been writing something on the
810 	 * screen and syscons is not aware of it. Declare the screen
811 	 * is NOT idle if it is in one of these modes. But there is
812 	 * an exception to it; if a screen saver is running in the
813 	 * graphics mode in the current screen, we should say that the
814 	 * screen has been idle.
815 	 */
816 	*(int *)data = (sc->flags & SC_SCRN_IDLE)
817 		       && (!ISGRAPHSC(sc->cur_scp)
818 			   || (sc->cur_scp->status & SAVER_RUNNING));
819 	return 0;
820 
821     case CONS_SAVERMODE:	/* set saver mode */
822 	switch(*(int *)data) {
823 	case CONS_USR_SAVER:
824 	    /* if a LKM screen saver is running, stop it first. */
825 	    scsplash_stick(FALSE);
826 	    saver_mode = *(int *)data;
827 	    s = spltty();
828 #if NSPLASH > 0
829 	    if ((error = wait_scrn_saver_stop(NULL))) {
830 		splx(s);
831 		return error;
832 	    }
833 #endif /* NSPLASH */
834 	    run_scrn_saver = TRUE;
835 	    scp->status |= SAVER_RUNNING;
836 	    scsplash_stick(TRUE);
837 	    splx(s);
838 	    break;
839 	case CONS_LKM_SAVER:
840 	    s = spltty();
841 	    if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
842 		scp->status &= ~SAVER_RUNNING;
843 	    saver_mode = *(int *)data;
844 	    splx(s);
845 	    break;
846 	default:
847 	    return EINVAL;
848 	}
849 	return 0;
850 
851     case CONS_SAVERSTART:	/* immediately start/stop the screen saver */
852 	/*
853 	 * Note that this ioctl does not guarantee the screen saver
854 	 * actually starts or stops. It merely attempts to do so...
855 	 */
856 	s = spltty();
857 	run_scrn_saver = (*(int *)data != 0);
858 	if (run_scrn_saver)
859 	    sc->scrn_time_stamp -= scrn_blank_time;
860 	splx(s);
861 	return 0;
862 
863     case VT_SETMODE:    	/* set screen switcher mode */
864     {
865 	struct vt_mode *mode;
866 
867 	mode = (struct vt_mode *)data;
868 	DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
869 	if (scp->smode.mode == VT_PROCESS) {
870     	    if (scp->proc == pfind(scp->pid) && scp->proc != p) {
871 		DPRINTF(5, ("error EPERM\n"));
872 		return EPERM;
873 	    }
874 	}
875 	s = spltty();
876 	if (mode->mode == VT_AUTO) {
877 	    scp->smode.mode = VT_AUTO;
878 	    scp->proc = NULL;
879 	    scp->pid = 0;
880 	    DPRINTF(5, ("VT_AUTO, "));
881 	    if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
882 		cons_unavail = FALSE;
883 	    /* were we in the middle of the vty switching process? */
884 	    if (scp->status & SWITCH_WAIT_REL) {
885 		/* assert(scp == scp->sc->cur_scp) */
886 		DPRINTF(5, ("reset WAIT_REL, "));
887 		scp->status &= ~SWITCH_WAIT_REL;
888 		s = do_switch_scr(sc, s);
889 	    }
890 	    if (scp->status & SWITCH_WAIT_ACQ) {
891 		/* assert(scp == scp->sc->cur_scp) */
892 		DPRINTF(5, ("reset WAIT_ACQ, "));
893 		scp->status &= ~SWITCH_WAIT_ACQ;
894 		sc->switch_in_progress = 0;
895 	    }
896 	} else {
897 	    if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
898 		|| !ISSIGVALID(mode->frsig)) {
899 		splx(s);
900 		DPRINTF(5, ("error EINVAL\n"));
901 		return EINVAL;
902 	    }
903 	    DPRINTF(5, ("VT_PROCESS %d, ", p->p_pid));
904 	    bcopy(data, &scp->smode, sizeof(struct vt_mode));
905 	    scp->proc = p;
906 	    scp->pid = scp->proc->p_pid;
907 	    if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
908 		cons_unavail = TRUE;
909 	}
910 	splx(s);
911 	DPRINTF(5, ("\n"));
912 	return 0;
913     }
914 
915     case VT_GETMODE:    	/* get screen switcher mode */
916 	bcopy(&scp->smode, data, sizeof(struct vt_mode));
917 	return 0;
918 
919     case VT_RELDISP:    	/* screen switcher ioctl */
920 	s = spltty();
921 	/*
922 	 * This must be the current vty which is in the VT_PROCESS
923 	 * switching mode...
924 	 */
925 	if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
926 	    splx(s);
927 	    return EINVAL;
928 	}
929 	/* ...and this process is controlling it. */
930 	if (scp->proc != p) {
931 	    splx(s);
932 	    return EPERM;
933 	}
934 	error = EINVAL;
935 	switch(*(int *)data) {
936 	case VT_FALSE:  	/* user refuses to release screen, abort */
937 	    if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
938 		sc->old_scp->status &= ~SWITCH_WAIT_REL;
939 		sc->switch_in_progress = 0;
940 		DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
941 		error = 0;
942 	    }
943 	    break;
944 
945 	case VT_TRUE:   	/* user has released screen, go on */
946 	    if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
947 		scp->status &= ~SWITCH_WAIT_REL;
948 		s = do_switch_scr(sc, s);
949 		DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
950 		error = 0;
951 	    }
952 	    break;
953 
954 	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
955 	    if ((scp == sc->new_scp) && (scp->status & SWITCH_WAIT_ACQ)) {
956 		scp->status &= ~SWITCH_WAIT_ACQ;
957 		sc->switch_in_progress = 0;
958 		DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
959 		error = 0;
960 	    }
961 	    break;
962 
963 	default:
964 	    break;
965 	}
966 	splx(s);
967 	return error;
968 
969     case VT_OPENQRY:    	/* return free virtual console */
970 	for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
971 	    tp = VIRTUAL_TTY(sc, i);
972 	    if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
973 		*(int *)data = i + 1;
974 		return 0;
975 	    }
976 	}
977 	return EINVAL;
978 
979     case VT_ACTIVATE:   	/* switch to screen *data */
980 	s = spltty();
981 	sc_clean_up(sc->cur_scp);
982 	splx(s);
983 	return switch_scr(sc, *(int *)data - 1);
984 
985     case VT_WAITACTIVE: 	/* wait for switch to occur */
986 	if ((*(int *)data >= sc->first_vty + sc->vtys)
987 		|| (*(int *)data < sc->first_vty))
988 	    return EINVAL;
989 	s = spltty();
990 	error = sc_clean_up(sc->cur_scp);
991 	splx(s);
992 	if (error)
993 	    return error;
994 	if (*(int *)data != 0)
995 	    scp = SC_STAT(SC_DEV(sc, *(int *)data - 1));
996 	if (scp == scp->sc->cur_scp)
997 	    return 0;
998 	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
999 			     "waitvt", 0)) == ERESTART) ;
1000 	return error;
1001 
1002     case VT_GETACTIVE:		/* get active vty # */
1003 	*(int *)data = sc->cur_scp->index + 1;
1004 	return 0;
1005 
1006     case VT_GETINDEX:		/* get this vty # */
1007 	*(int *)data = scp->index + 1;
1008 	return 0;
1009 
1010     case KDENABIO:      	/* allow io operations */
1011 	error = suser(p);
1012 	if (error != 0)
1013 	    return error;
1014 	if (securelevel > 0)
1015 	    return EPERM;
1016 #ifdef __i386__
1017 	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1018 #endif
1019 	return 0;
1020 
1021     case KDDISABIO:     	/* disallow io operations (default) */
1022 #ifdef __i386__
1023 	p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1024 #endif
1025 	return 0;
1026 
1027     case KDSKBSTATE:    	/* set keyboard state (locks) */
1028 	if (*(int *)data & ~LOCK_MASK)
1029 	    return EINVAL;
1030 	scp->status &= ~LOCK_MASK;
1031 	scp->status |= *(int *)data;
1032 	if (scp == sc->cur_scp)
1033 	    update_kbd_state(scp, scp->status, LOCK_MASK);
1034 	return 0;
1035 
1036     case KDGKBSTATE:    	/* get keyboard state (locks) */
1037 	if (scp == sc->cur_scp)
1038 	    save_kbd_state(scp);
1039 	*(int *)data = scp->status & LOCK_MASK;
1040 	return 0;
1041 
1042     case KDSETREPEAT:      	/* set keyboard repeat & delay rates (new) */
1043 	error = kbd_ioctl(sc->kbd, cmd, data);
1044 	if (error == ENOIOCTL)
1045 	    error = ENODEV;
1046 	return error;
1047 
1048     case KDSETRAD:      	/* set keyboard repeat & delay rates (old) */
1049 	if (*(int *)data & ~0x7f)
1050 	    return EINVAL;
1051 	error = kbd_ioctl(sc->kbd, cmd, data);
1052 	if (error == ENOIOCTL)
1053 	    error = ENODEV;
1054 	return error;
1055 
1056     case KDSKBMODE:     	/* set keyboard mode */
1057 	switch (*(int *)data) {
1058 	case K_XLATE:   	/* switch to XLT ascii mode */
1059 	case K_RAW: 		/* switch to RAW scancode mode */
1060 	case K_CODE: 		/* switch to CODE mode */
1061 	    scp->kbd_mode = *(int *)data;
1062 	    if (scp == sc->cur_scp)
1063 		kbd_ioctl(sc->kbd, cmd, data);
1064 	    return 0;
1065 	default:
1066 	    return EINVAL;
1067 	}
1068 	/* NOT REACHED */
1069 
1070     case KDGKBMODE:     	/* get keyboard mode */
1071 	*(int *)data = scp->kbd_mode;
1072 	return 0;
1073 
1074     case KDGKBINFO:
1075 	error = kbd_ioctl(sc->kbd, cmd, data);
1076 	if (error == ENOIOCTL)
1077 	    error = ENODEV;
1078 	return error;
1079 
1080     case KDMKTONE:      	/* sound the bell */
1081 	if (*(int*)data)
1082 	    do_bell(scp, (*(int*)data)&0xffff,
1083 		    (((*(int*)data)>>16)&0xffff)*hz/1000);
1084 	else
1085 	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1086 	return 0;
1087 
1088     case KIOCSOUND:     	/* make tone (*data) hz */
1089 	if (scp == sc->cur_scp) {
1090 	    if (*(int *)data)
1091 		return sc_tone(*(int *)data);
1092 	    else
1093 		return sc_tone(0);
1094 	}
1095 	return 0;
1096 
1097     case KDGKBTYPE:     	/* get keyboard type */
1098 	error = kbd_ioctl(sc->kbd, cmd, data);
1099 	if (error == ENOIOCTL) {
1100 	    /* always return something? XXX */
1101 	    *(int *)data = 0;
1102 	}
1103 	return 0;
1104 
1105     case KDSETLED:      	/* set keyboard LED status */
1106 	if (*(int *)data & ~LED_MASK)	/* FIXME: LOCK_MASK? */
1107 	    return EINVAL;
1108 	scp->status &= ~LED_MASK;
1109 	scp->status |= *(int *)data;
1110 	if (scp == sc->cur_scp)
1111 	    update_kbd_leds(scp, scp->status);
1112 	return 0;
1113 
1114     case KDGETLED:      	/* get keyboard LED status */
1115 	if (scp == sc->cur_scp)
1116 	    save_kbd_state(scp);
1117 	*(int *)data = scp->status & LED_MASK;
1118 	return 0;
1119 
1120     case CONS_SETKBD: 		/* set the new keyboard */
1121 	{
1122 	    keyboard_t *newkbd;
1123 
1124 	    s = spltty();
1125 	    newkbd = kbd_get_keyboard(*(int *)data);
1126 	    if (newkbd == NULL) {
1127 		splx(s);
1128 		return EINVAL;
1129 	    }
1130 	    error = 0;
1131 	    if (sc->kbd != newkbd) {
1132 		i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1133 				 (void *)&sc->keyboard, sckbdevent, sc);
1134 		/* i == newkbd->kb_index */
1135 		if (i >= 0) {
1136 		    if (sc->kbd != NULL) {
1137 			save_kbd_state(sc->cur_scp);
1138 			kbd_release(sc->kbd, (void *)&sc->keyboard);
1139 		    }
1140 		    sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1141 		    sc->keyboard = i;
1142 		    kbd_ioctl(sc->kbd, KDSKBMODE,
1143 			      (caddr_t)&sc->cur_scp->kbd_mode);
1144 		    update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1145 				     LOCK_MASK);
1146 		} else {
1147 		    error = EPERM;	/* XXX */
1148 		}
1149 	    }
1150 	    splx(s);
1151 	    return error;
1152 	}
1153 
1154     case CONS_RELKBD: 		/* release the current keyboard */
1155 	s = spltty();
1156 	error = 0;
1157 	if (sc->kbd != NULL) {
1158 	    save_kbd_state(sc->cur_scp);
1159 	    error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1160 	    if (error == 0) {
1161 		sc->kbd = NULL;
1162 		sc->keyboard = -1;
1163 	    }
1164 	}
1165 	splx(s);
1166 	return error;
1167 
1168     case GIO_SCRNMAP:   	/* get output translation table */
1169 	bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
1170 	return 0;
1171 
1172     case PIO_SCRNMAP:   	/* set output translation table */
1173 	bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1174 	for (i=0; i<sizeof(sc->scr_map); i++) {
1175 	    sc->scr_rmap[sc->scr_map[i]] = i;
1176 	}
1177 	return 0;
1178 
1179     case GIO_KEYMAP:		/* get keyboard translation table */
1180     case PIO_KEYMAP:		/* set keyboard translation table */
1181     case GIO_DEADKEYMAP:	/* get accent key translation table */
1182     case PIO_DEADKEYMAP:	/* set accent key translation table */
1183     case GETFKEY:		/* get function key string */
1184     case SETFKEY:		/* set function key string */
1185 	error = kbd_ioctl(sc->kbd, cmd, data);
1186 	if (error == ENOIOCTL)
1187 	    error = ENODEV;
1188 	return error;
1189 
1190 #ifndef SC_NO_FONT_LOADING
1191 
1192     case PIO_FONT8x8:   	/* set 8x8 dot font */
1193 	if (!ISFONTAVAIL(sc->adp->va_flags))
1194 	    return ENXIO;
1195 	bcopy(data, sc->font_8, 8*256);
1196 	sc->fonts_loaded |= FONT_8;
1197 	/*
1198 	 * FONT KLUDGE
1199 	 * Always use the font page #0. XXX
1200 	 * Don't load if the current font size is not 8x8.
1201 	 */
1202 	if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14))
1203 	    copy_font(sc->cur_scp, LOAD, 8, sc->font_8);
1204 	return 0;
1205 
1206     case GIO_FONT8x8:   	/* get 8x8 dot font */
1207 	if (!ISFONTAVAIL(sc->adp->va_flags))
1208 	    return ENXIO;
1209 	if (sc->fonts_loaded & FONT_8) {
1210 	    bcopy(sc->font_8, data, 8*256);
1211 	    return 0;
1212 	}
1213 	else
1214 	    return ENXIO;
1215 
1216     case PIO_FONT8x14:  	/* set 8x14 dot font */
1217 	if (!ISFONTAVAIL(sc->adp->va_flags))
1218 	    return ENXIO;
1219 	bcopy(data, sc->font_14, 14*256);
1220 	sc->fonts_loaded |= FONT_14;
1221 	/*
1222 	 * FONT KLUDGE
1223 	 * Always use the font page #0. XXX
1224 	 * Don't load if the current font size is not 8x14.
1225 	 */
1226 	if (ISTEXTSC(sc->cur_scp)
1227 	    && (sc->cur_scp->font_size >= 14)
1228 	    && (sc->cur_scp->font_size < 16))
1229 	    copy_font(sc->cur_scp, LOAD, 14, sc->font_14);
1230 	return 0;
1231 
1232     case GIO_FONT8x14:  	/* get 8x14 dot font */
1233 	if (!ISFONTAVAIL(sc->adp->va_flags))
1234 	    return ENXIO;
1235 	if (sc->fonts_loaded & FONT_14) {
1236 	    bcopy(sc->font_14, data, 14*256);
1237 	    return 0;
1238 	}
1239 	else
1240 	    return ENXIO;
1241 
1242     case PIO_FONT8x16:  	/* set 8x16 dot font */
1243 	if (!ISFONTAVAIL(sc->adp->va_flags))
1244 	    return ENXIO;
1245 	bcopy(data, sc->font_16, 16*256);
1246 	sc->fonts_loaded |= FONT_16;
1247 	/*
1248 	 * FONT KLUDGE
1249 	 * Always use the font page #0. XXX
1250 	 * Don't load if the current font size is not 8x16.
1251 	 */
1252 	if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16))
1253 	    copy_font(sc->cur_scp, LOAD, 16, sc->font_16);
1254 	return 0;
1255 
1256     case GIO_FONT8x16:  	/* get 8x16 dot font */
1257 	if (!ISFONTAVAIL(sc->adp->va_flags))
1258 	    return ENXIO;
1259 	if (sc->fonts_loaded & FONT_16) {
1260 	    bcopy(sc->font_16, data, 16*256);
1261 	    return 0;
1262 	}
1263 	else
1264 	    return ENXIO;
1265 
1266 #endif /* SC_NO_FONT_LOADING */
1267 
1268     default:
1269 	break;
1270     }
1271 
1272     error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1273     if (error != ENOIOCTL)
1274 	return(error);
1275     error = ttioctl(tp, cmd, data, flag);
1276     if (error != ENOIOCTL)
1277 	return(error);
1278     return(ENOTTY);
1279 }
1280 
1281 static void
1282 scstart(struct tty *tp)
1283 {
1284     struct clist *rbp;
1285     int s, len;
1286     u_char buf[PCBURST];
1287     scr_stat *scp = SC_STAT(tp->t_dev);
1288 
1289     if (scp->status & SLKED || scp->sc->blink_in_progress)
1290 	return;
1291     s = spltty();
1292     if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1293 	tp->t_state |= TS_BUSY;
1294 	rbp = &tp->t_outq;
1295 	while (rbp->c_cc) {
1296 	    len = q_to_b(rbp, buf, PCBURST);
1297 	    splx(s);
1298 	    ansi_put(scp, buf, len);
1299 	    s = spltty();
1300 	}
1301 	tp->t_state &= ~TS_BUSY;
1302 	ttwwakeup(tp);
1303     }
1304     splx(s);
1305 }
1306 
1307 static void
1308 scmousestart(struct tty *tp)
1309 {
1310     struct clist *rbp;
1311     int s;
1312     u_char buf[PCBURST];
1313 
1314     s = spltty();
1315     if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1316 	tp->t_state |= TS_BUSY;
1317 	rbp = &tp->t_outq;
1318 	while (rbp->c_cc) {
1319 	    q_to_b(rbp, buf, PCBURST);
1320 	}
1321 	tp->t_state &= ~TS_BUSY;
1322 	ttwwakeup(tp);
1323     }
1324     splx(s);
1325 }
1326 
1327 static void
1328 sccnprobe(struct consdev *cp)
1329 {
1330 #if __i386__
1331     int unit;
1332     int flags;
1333 
1334     cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1335 
1336     /* a video card is always required */
1337     if (!scvidprobe(unit, flags, TRUE))
1338 	cp->cn_pri = CN_DEAD;
1339 
1340     /* syscons will become console even when there is no keyboard */
1341     sckbdprobe(unit, flags, TRUE);
1342 
1343     if (cp->cn_pri == CN_DEAD)
1344 	return;
1345 
1346     /* initialize required fields */
1347     cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLECTL);
1348 #endif /* __i386__ */
1349 
1350 #if __alpha__
1351     /*
1352      * alpha use sccnattach() rather than cnprobe()/cninit()/cnterm()
1353      * interface to install the console.  Always return CN_DEAD from
1354      * here.
1355      */
1356     cp->cn_pri = CN_DEAD;
1357 #endif /* __alpha__ */
1358 }
1359 
1360 static void
1361 sccninit(struct consdev *cp)
1362 {
1363 #if __i386__
1364     int unit;
1365     int flags;
1366 
1367     sc_get_cons_priority(&unit, &flags);
1368     scinit(unit, flags | SC_KERNEL_CONSOLE);
1369     sc_console_unit = unit;
1370     sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1371 #endif /* __i386__ */
1372 
1373 #if __alpha__
1374     /* SHOULDN'T REACH HERE */
1375 #endif /* __alpha__ */
1376 }
1377 
1378 static void
1379 sccnterm(struct consdev *cp)
1380 {
1381     /* we are not the kernel console any more, release everything */
1382 
1383     if (sc_console_unit < 0)
1384 	return;			/* shouldn't happen */
1385 
1386 #if __i386__
1387 #if 0 /* XXX */
1388     sc_clear_screen(sc_console);
1389     sccnupdate(sc_console);
1390 #endif
1391     scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1392     sc_console_unit = -1;
1393     sc_console = NULL;
1394 #endif /* __i386__ */
1395 
1396 #if __alpha__
1397     /* do nothing XXX */
1398 #endif /* __alpha__ */
1399 }
1400 
1401 #ifdef __alpha__
1402 
1403 void
1404 sccnattach(void)
1405 {
1406     static struct consdev consdev;
1407     int unit;
1408     int flags;
1409 
1410     bcopy(&sc_consdev, &consdev, sizeof(sc_consdev));
1411     consdev.cn_pri = sc_get_cons_priority(&unit, &flags);
1412 
1413     /* a video card is always required */
1414     if (!scvidprobe(unit, flags, TRUE))
1415 	consdev.cn_pri = CN_DEAD;
1416 
1417     /* alpha doesn't allow the console being without a keyboard... Why? */
1418     if (!sckbdprobe(unit, flags, TRUE))
1419 	consdev.cn_pri = CN_DEAD;
1420 
1421     if (consdev.cn_pri == CN_DEAD)
1422 	return;
1423 
1424     scinit(unit, flags | SC_KERNEL_CONSOLE);
1425     sc_console_unit = unit;
1426     sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1427     consdev.cn_dev = makedev(CDEV_MAJOR, 0);
1428     cn_tab = &consdev;
1429 }
1430 
1431 #endif /* __alpha__ */
1432 
1433 static void
1434 sccnputc(dev_t dev, int c)
1435 {
1436     u_char buf[1];
1437     scr_stat *scp = sc_console;
1438     term_stat save = scp->term;
1439 #ifndef SC_NO_HISTORY
1440     struct tty *tp;
1441 #endif /* !SC_NO_HISTORY */
1442     int s;
1443 
1444     /* assert(sc_console != NULL) */
1445 
1446 #ifndef SC_NO_HISTORY
1447     if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1448 	scp->status &= ~SLKED;
1449 	update_kbd_state(scp, scp->status, SLKED);
1450 	if (scp->status & BUFFER_SAVED) {
1451 	    if (!sc_hist_restore(scp))
1452 		sc_remove_cutmarking(scp);
1453 	    scp->status &= ~BUFFER_SAVED;
1454 	    scp->status |= CURSOR_ENABLED;
1455 	    draw_cursor_image(scp);
1456 	}
1457 	tp = VIRTUAL_TTY(scp->sc, scp->index);
1458 	if (tp->t_state & TS_ISOPEN)
1459 	    scstart(tp);
1460     }
1461 #endif /* !SC_NO_HISTORY */
1462 
1463     scp->term = kernel_console;
1464     current_default = &kernel_default;
1465     buf[0] = c;
1466     ansi_put(scp, buf, 1);
1467     kernel_console = scp->term;
1468     current_default = &user_default;
1469     scp->term = save;
1470 
1471     s = spltty();	/* block sckbdevent and scrn_timer */
1472     sccnupdate(scp);
1473     splx(s);
1474 }
1475 
1476 static int
1477 sccngetc(dev_t dev)
1478 {
1479     return sccngetch(0);
1480 }
1481 
1482 static int
1483 sccncheckc(dev_t dev)
1484 {
1485     return sccngetch(SCGETC_NONBLOCK);
1486 }
1487 
1488 static int
1489 sccngetch(int flags)
1490 {
1491     static struct fkeytab fkey;
1492     static int fkeycp;
1493     scr_stat *scp;
1494     u_char *p;
1495     int cur_mode;
1496     int s = spltty();	/* block sckbdevent and scrn_timer while we poll */
1497     int c;
1498 
1499     /* assert(sc_console != NULL) */
1500 
1501     /*
1502      * Stop the screen saver and update the screen if necessary.
1503      * What if we have been running in the screen saver code... XXX
1504      */
1505     sc_touch_scrn_saver();
1506     scp = sc_console->sc->cur_scp;	/* XXX */
1507     sccnupdate(scp);
1508 
1509     if (fkeycp < fkey.len) {
1510 	splx(s);
1511 	return fkey.str[fkeycp++];
1512     }
1513 
1514     if (scp->sc->kbd == NULL) {
1515 	splx(s);
1516 	return -1;
1517     }
1518 
1519     /*
1520      * Make sure the keyboard is accessible even when the kbd device
1521      * driver is disabled.
1522      */
1523     kbd_enable(scp->sc->kbd);
1524 
1525     /* we shall always use the keyboard in the XLATE mode here */
1526     cur_mode = scp->kbd_mode;
1527     scp->kbd_mode = K_XLATE;
1528     kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1529 
1530     kbd_poll(scp->sc->kbd, TRUE);
1531     c = scgetc(scp->sc, SCGETC_CN | flags);
1532     kbd_poll(scp->sc->kbd, FALSE);
1533 
1534     scp->kbd_mode = cur_mode;
1535     kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1536     kbd_disable(scp->sc->kbd);
1537     splx(s);
1538 
1539     switch (KEYFLAGS(c)) {
1540     case 0:	/* normal char */
1541 	return KEYCHAR(c);
1542     case FKEY:	/* function key */
1543 	p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
1544 	fkey.len = fkeycp;
1545 	if ((p != NULL) && (fkey.len > 0)) {
1546 	    bcopy(p, fkey.str, fkey.len);
1547 	    fkeycp = 1;
1548 	    return fkey.str[0];
1549 	}
1550 	return c;	/* XXX */
1551     case NOKEY:
1552     case ERRKEY:
1553     default:
1554 	return -1;
1555     }
1556     /* NOT REACHED */
1557 }
1558 
1559 static void
1560 sccnupdate(scr_stat *scp)
1561 {
1562     /* this is a cut-down version of scrn_timer()... */
1563 
1564     if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress)
1565 	return;
1566 
1567     if (debugger || panicstr || shutdown_in_progress) {
1568 	sc_touch_scrn_saver();
1569     } else if (scp != scp->sc->cur_scp) {
1570 	return;
1571     }
1572 
1573     if (!run_scrn_saver)
1574 	scp->sc->flags &= ~SC_SCRN_IDLE;
1575 #if NSPLASH > 0
1576     if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1577 	if (scp->sc->flags & SC_SCRN_BLANKED)
1578             stop_scrn_saver(scp->sc, current_saver);
1579 #endif /* NSPLASH */
1580 
1581     if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
1582 	|| scp->sc->switch_in_progress)
1583 	return;
1584     /*
1585      * FIXME: unlike scrn_timer(), we call scrn_update() from here even
1586      * when write_in_progress is non-zero.  XXX
1587      */
1588 
1589     if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1590 	scrn_update(scp, TRUE);
1591 }
1592 
1593 static void
1594 scrn_timer(void *arg)
1595 {
1596     static int kbd_interval = 0;
1597     struct timeval tv;
1598     sc_softc_t *sc;
1599     scr_stat *scp;
1600     int again;
1601     int s;
1602 
1603     again = (arg != NULL);
1604     if (arg != NULL)
1605 	sc = (sc_softc_t *)arg;
1606     else if (sc_console != NULL)
1607 	sc = sc_console->sc;
1608     else
1609 	return;
1610 
1611     /* don't do anything when we are performing some I/O operations */
1612     if (sc->font_loading_in_progress || sc->videoio_in_progress) {
1613 	if (again)
1614 	    timeout(scrn_timer, sc, hz / 10);
1615 	return;
1616     }
1617     s = spltty();
1618 
1619     if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
1620 	/* try to allocate a keyboard automatically */
1621 	if (++kbd_interval >= 25) {
1622 	    sc->keyboard = kbd_allocate("*", -1, (void *)&sc->keyboard,
1623 					sckbdevent, sc);
1624 	    if (sc->keyboard >= 0) {
1625 		sc->kbd = kbd_get_keyboard(sc->keyboard);
1626 		kbd_ioctl(sc->kbd, KDSKBMODE,
1627 			  (caddr_t)&sc->cur_scp->kbd_mode);
1628 		update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1629 				 LOCK_MASK);
1630 	    }
1631 	    kbd_interval = 0;
1632 	}
1633     }
1634 
1635     /* find the vty to update */
1636     scp = sc->cur_scp;
1637 
1638     /* should we stop the screen saver? */
1639     getmicrouptime(&tv);
1640     if (debugger || panicstr || shutdown_in_progress)
1641 	sc_touch_scrn_saver();
1642     if (run_scrn_saver) {
1643 	if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
1644 	    sc->flags |= SC_SCRN_IDLE;
1645 	else
1646 	    sc->flags &= ~SC_SCRN_IDLE;
1647     } else {
1648 	sc->scrn_time_stamp = tv.tv_sec;
1649 	sc->flags &= ~SC_SCRN_IDLE;
1650 	if (scrn_blank_time > 0)
1651 	    run_scrn_saver = TRUE;
1652     }
1653 #if NSPLASH > 0
1654     if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE))
1655 	if (sc->flags & SC_SCRN_BLANKED)
1656             stop_scrn_saver(sc, current_saver);
1657 #endif /* NSPLASH */
1658 
1659     /* should we just return ? */
1660     if (sc->blink_in_progress || sc->switch_in_progress
1661 	|| sc->write_in_progress) {
1662 	if (again)
1663 	    timeout(scrn_timer, sc, hz / 10);
1664 	splx(s);
1665 	return;
1666     }
1667 
1668     /* Update the screen */
1669     scp = sc->cur_scp;		/* cur_scp may have changed... */
1670     if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1671 	scrn_update(scp, TRUE);
1672 
1673 #if NSPLASH > 0
1674     /* should we activate the screen saver? */
1675     if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
1676 	if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
1677 	    (*current_saver)(sc, TRUE);
1678 #endif /* NSPLASH */
1679 
1680     if (again)
1681 	timeout(scrn_timer, sc, hz / 25);
1682     splx(s);
1683 }
1684 
1685 static int
1686 and_region(int *s1, int *e1, int s2, int e2)
1687 {
1688     if (*e1 < s2 || e2 < *s1)
1689 	return FALSE;
1690     *s1 = imax(*s1, s2);
1691     *e1 = imin(*e1, e2);
1692     return TRUE;
1693 }
1694 
1695 static void
1696 scrn_update(scr_stat *scp, int show_cursor)
1697 {
1698     int start;
1699     int end;
1700     int s;
1701     int e;
1702 
1703     /* assert(scp == scp->sc->cur_scp) */
1704 
1705     ++scp->sc->videoio_in_progress;
1706 
1707 #ifndef SC_NO_CUTPASTE
1708     /* remove the previous mouse pointer image if necessary */
1709     if ((scp->status & (MOUSE_VISIBLE | MOUSE_MOVED))
1710 	== (MOUSE_VISIBLE | MOUSE_MOVED)) {
1711 	/* FIXME: I don't like this... XXX */
1712 	sc_remove_mouse_image(scp);
1713         if (scp->end >= scp->xsize*scp->ysize)
1714 	    scp->end = scp->xsize*scp->ysize - 1;
1715     }
1716 #endif /* !SC_NO_CUTPASTE */
1717 
1718 #if 1
1719     /* debug: XXX */
1720     if (scp->end >= scp->xsize*scp->ysize) {
1721 	printf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end);
1722 	scp->end = scp->xsize*scp->ysize - 1;
1723     }
1724     if (scp->start < 0) {
1725 	printf("scrn_update(): scp->start %d < 0\n", scp->start);
1726 	scp->start = 0;
1727     }
1728 #endif
1729 
1730     /* update screen image */
1731     if (scp->start <= scp->end)  {
1732 	if (scp->mouse_cut_end >= 0) {
1733 	    /* there is a marked region for cut & paste */
1734 	    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
1735 		start = scp->mouse_cut_start;
1736 		end = scp->mouse_cut_end;
1737 	    } else {
1738 		start = scp->mouse_cut_end;
1739 		end = scp->mouse_cut_start - 1;
1740 	    }
1741 	    s = start;
1742 	    e = end;
1743 	    /* does the cut-mark region overlap with the update region? */
1744 	    if (and_region(&s, &e, scp->start, scp->end)) {
1745 		(*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
1746 		s = 0;
1747 		e = start - 1;
1748 		if (and_region(&s, &e, scp->start, scp->end))
1749 		    (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1750 		s = end + 1;
1751 		e = scp->xsize*scp->ysize - 1;
1752 		if (and_region(&s, &e, scp->start, scp->end))
1753 		    (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1754 	    } else {
1755 		(*scp->rndr->draw)(scp, scp->start,
1756 				   scp->end - scp->start + 1, FALSE);
1757 	    }
1758 	} else {
1759 	    (*scp->rndr->draw)(scp, scp->start,
1760 			       scp->end - scp->start + 1, FALSE);
1761 	}
1762     }
1763 
1764     /* we are not to show the cursor and the mouse pointer... */
1765     if (!show_cursor) {
1766         scp->end = 0;
1767         scp->start = scp->xsize*scp->ysize - 1;
1768 	--scp->sc->videoio_in_progress;
1769 	return;
1770     }
1771 
1772     /* update cursor image */
1773     if (scp->status & CURSOR_ENABLED) {
1774         /* did cursor move since last time ? */
1775         if (scp->cursor_pos != scp->cursor_oldpos) {
1776             /* do we need to remove old cursor image ? */
1777             if (scp->cursor_oldpos < scp->start ||
1778                 scp->cursor_oldpos > scp->end) {
1779                 remove_cursor_image(scp);
1780             }
1781             scp->cursor_oldpos = scp->cursor_pos;
1782             draw_cursor_image(scp);
1783         }
1784         else {
1785             /* cursor didn't move, has it been overwritten ? */
1786             if (scp->cursor_pos >= scp->start && scp->cursor_pos <= scp->end) {
1787                 draw_cursor_image(scp);
1788             } else {
1789                 /* if its a blinking cursor, we may have to update it */
1790 		if (scp->sc->flags & SC_BLINK_CURSOR)
1791                     (*scp->rndr->blink_cursor)(scp, scp->cursor_pos,
1792 					       sc_inside_cutmark(scp,
1793 							scp->cursor_pos));
1794             }
1795         }
1796     }
1797 
1798 #ifndef SC_NO_CUTPASTE
1799     /* update "pseudo" mouse pointer image */
1800     if (scp->status & MOUSE_VISIBLE) {
1801         /* did mouse move since last time ? */
1802         if (scp->status & MOUSE_MOVED) {
1803             /* the previous pointer image has been removed, see above */
1804             scp->status &= ~MOUSE_MOVED;
1805             sc_draw_mouse_image(scp);
1806         } else {
1807             /* mouse didn't move, has it been overwritten ? */
1808             if (scp->mouse_pos + scp->xsize + 1 >= scp->start &&
1809                 scp->mouse_pos <= scp->end) {
1810                 sc_draw_mouse_image(scp);
1811             } else if (scp->cursor_pos == scp->mouse_pos ||
1812             	scp->cursor_pos == scp->mouse_pos + 1 ||
1813             	scp->cursor_pos == scp->mouse_pos + scp->xsize ||
1814             	scp->cursor_pos == scp->mouse_pos + scp->xsize + 1) {
1815                 sc_draw_mouse_image(scp);
1816 	    }
1817         }
1818     }
1819 #endif /* SC_NO_CUTPASTE */
1820 
1821     scp->end = 0;
1822     scp->start = scp->xsize*scp->ysize - 1;
1823 
1824     --scp->sc->videoio_in_progress;
1825 }
1826 
1827 #if NSPLASH > 0
1828 static int
1829 scsplash_callback(int event, void *arg)
1830 {
1831     sc_softc_t *sc;
1832     int error;
1833 
1834     sc = (sc_softc_t *)arg;
1835 
1836     switch (event) {
1837     case SPLASH_INIT:
1838 	if (add_scrn_saver(scsplash_saver) == 0) {
1839 	    sc->flags &= ~SC_SAVER_FAILED;
1840 	    run_scrn_saver = TRUE;
1841 	    if (cold && !(boothowto & (RB_VERBOSE | RB_CONFIG))) {
1842 		scsplash_stick(TRUE);
1843 		(*current_saver)(sc, TRUE);
1844 	    }
1845 	}
1846 	return 0;
1847 
1848     case SPLASH_TERM:
1849 	if (current_saver == scsplash_saver) {
1850 	    scsplash_stick(FALSE);
1851 	    error = remove_scrn_saver(scsplash_saver);
1852 	    if (error)
1853 		return error;
1854 	}
1855 	return 0;
1856 
1857     default:
1858 	return EINVAL;
1859     }
1860 }
1861 
1862 static void
1863 scsplash_saver(sc_softc_t *sc, int show)
1864 {
1865     static int busy = FALSE;
1866     scr_stat *scp;
1867 
1868     if (busy)
1869 	return;
1870     busy = TRUE;
1871 
1872     scp = sc->cur_scp;
1873     if (show) {
1874 	if (!(sc->flags & SC_SAVER_FAILED)) {
1875 	    if (!(sc->flags & SC_SCRN_BLANKED))
1876 		set_scrn_saver_mode(scp, -1, NULL, 0);
1877 	    switch (splash(sc->adp, TRUE)) {
1878 	    case 0:		/* succeeded */
1879 		break;
1880 	    case EAGAIN:	/* try later */
1881 		restore_scrn_saver_mode(scp, FALSE);
1882 		sc_touch_scrn_saver();		/* XXX */
1883 		break;
1884 	    default:
1885 		sc->flags |= SC_SAVER_FAILED;
1886 		scsplash_stick(FALSE);
1887 		restore_scrn_saver_mode(scp, TRUE);
1888 		printf("scsplash_saver(): failed to put up the image\n");
1889 		break;
1890 	    }
1891 	}
1892     } else if (!sticky_splash) {
1893 	if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
1894 	    restore_scrn_saver_mode(scp, TRUE);
1895     }
1896     busy = FALSE;
1897 }
1898 
1899 static int
1900 add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1901 {
1902 #if 0
1903     int error;
1904 
1905     if (current_saver != none_saver) {
1906 	error = remove_scrn_saver(current_saver);
1907 	if (error)
1908 	    return error;
1909     }
1910 #endif
1911     if (current_saver != none_saver)
1912 	return EBUSY;
1913 
1914     run_scrn_saver = FALSE;
1915     saver_mode = CONS_LKM_SAVER;
1916     current_saver = this_saver;
1917     return 0;
1918 }
1919 
1920 static int
1921 remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1922 {
1923     if (current_saver != this_saver)
1924 	return EINVAL;
1925 
1926 #if 0
1927     /*
1928      * In order to prevent `current_saver' from being called by
1929      * the timeout routine `scrn_timer()' while we manipulate
1930      * the saver list, we shall set `current_saver' to `none_saver'
1931      * before stopping the current saver, rather than blocking by `splXX()'.
1932      */
1933     current_saver = none_saver;
1934     if (scrn_blanked)
1935         stop_scrn_saver(this_saver);
1936 #endif
1937 
1938     /* unblank all blanked screens */
1939     wait_scrn_saver_stop(NULL);
1940     if (scrn_blanked)
1941 	return EBUSY;
1942 
1943     current_saver = none_saver;
1944     return 0;
1945 }
1946 
1947 static int
1948 set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
1949 {
1950     int s;
1951 
1952     /* assert(scp == scp->sc->cur_scp) */
1953     s = spltty();
1954     if (!ISGRAPHSC(scp))
1955 	remove_cursor_image(scp);
1956     scp->splash_save_mode = scp->mode;
1957     scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
1958     scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
1959     scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
1960     scp->sc->flags |= SC_SCRN_BLANKED;
1961     ++scrn_blanked;
1962     splx(s);
1963     if (mode < 0)
1964 	return 0;
1965     scp->mode = mode;
1966     if (set_mode(scp) == 0) {
1967 	if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS)
1968 	    scp->status |= GRAPHICS_MODE;
1969 #ifndef SC_NO_PALETTE_LOADING
1970 	if (pal != NULL)
1971 	    load_palette(scp->sc->adp, pal);
1972 #endif
1973 	set_border(scp, border);
1974 	return 0;
1975     } else {
1976 	s = spltty();
1977 	scp->mode = scp->splash_save_mode;
1978 	scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1979 	scp->status |= scp->splash_save_status;
1980 	splx(s);
1981 	return 1;
1982     }
1983 }
1984 
1985 static int
1986 restore_scrn_saver_mode(scr_stat *scp, int changemode)
1987 {
1988     int mode;
1989     int status;
1990     int s;
1991 
1992     /* assert(scp == scp->sc->cur_scp) */
1993     s = spltty();
1994     mode = scp->mode;
1995     status = scp->status;
1996     scp->mode = scp->splash_save_mode;
1997     scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1998     scp->status |= scp->splash_save_status;
1999     scp->sc->flags &= ~SC_SCRN_BLANKED;
2000     if (!changemode) {
2001 	if (!ISGRAPHSC(scp))
2002 	    draw_cursor_image(scp);
2003 	--scrn_blanked;
2004 	splx(s);
2005 	return 0;
2006     }
2007     if (set_mode(scp) == 0) {
2008 #ifndef SC_NO_PALETTE_LOADING
2009 	load_palette(scp->sc->adp, scp->sc->palette);
2010 #endif
2011 	--scrn_blanked;
2012 	splx(s);
2013 	return 0;
2014     } else {
2015 	scp->mode = mode;
2016 	scp->status = status;
2017 	splx(s);
2018 	return 1;
2019     }
2020 }
2021 
2022 static void
2023 stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
2024 {
2025     (*saver)(sc, FALSE);
2026     run_scrn_saver = FALSE;
2027     /* the screen saver may have chosen not to stop after all... */
2028     if (sc->flags & SC_SCRN_BLANKED)
2029 	return;
2030 
2031     mark_all(sc->cur_scp);
2032     if (sc->delayed_next_scr)
2033 	switch_scr(sc, sc->delayed_next_scr - 1);
2034     wakeup((caddr_t)&scrn_blanked);
2035 }
2036 
2037 static int
2038 wait_scrn_saver_stop(sc_softc_t *sc)
2039 {
2040     int error = 0;
2041 
2042     while (scrn_blanked > 0) {
2043 	run_scrn_saver = FALSE;
2044 	if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
2045 	    error = 0;
2046 	    break;
2047 	}
2048 	error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2049 	if ((error != 0) && (error != ERESTART))
2050 	    break;
2051     }
2052     run_scrn_saver = FALSE;
2053     return error;
2054 }
2055 #endif /* NSPLASH */
2056 
2057 void
2058 sc_touch_scrn_saver(void)
2059 {
2060     scsplash_stick(FALSE);
2061     run_scrn_saver = FALSE;
2062 }
2063 
2064 void
2065 sc_clear_screen(scr_stat *scp)
2066 {
2067     move_crsr(scp, 0, 0);
2068     scp->cursor_oldpos = scp->cursor_pos;
2069     sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], scp->term.cur_color);
2070     mark_all(scp);
2071     sc_remove_cutmarking(scp);
2072 }
2073 
2074 static int
2075 switch_scr(sc_softc_t *sc, u_int next_scr)
2076 {
2077     struct tty *tp;
2078     int s;
2079 
2080     DPRINTF(5, ("sc0: switch_scr() %d ", next_scr + 1));
2081 
2082     /* delay switch if the screen is blanked or being updated */
2083     if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2084 	|| sc->blink_in_progress || sc->videoio_in_progress) {
2085 	sc->delayed_next_scr = next_scr + 1;
2086 	sc_touch_scrn_saver();
2087 	DPRINTF(5, ("switch delayed\n"));
2088 	return 0;
2089     }
2090 
2091     s = spltty();
2092 
2093     /* we are in the middle of the vty switching process... */
2094     if (sc->switch_in_progress
2095 	&& (sc->cur_scp->smode.mode == VT_PROCESS)
2096 	&& sc->cur_scp->proc) {
2097 	if (sc->cur_scp->proc != pfind(sc->cur_scp->pid)) {
2098 	    /*
2099 	     * The controlling process has died!!.  Do some clean up.
2100 	     * NOTE:`cur_scp->proc' and `cur_scp->smode.mode'
2101 	     * are not reset here yet; they will be cleared later.
2102 	     */
2103 	    DPRINTF(5, ("cur_scp controlling process %d died, ",
2104 	       sc->cur_scp->pid));
2105 	    if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2106 		/*
2107 		 * Force the previous switch to finish, but return now
2108 		 * with error.
2109 		 */
2110 		DPRINTF(5, ("reset WAIT_REL, "));
2111 		sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2112 		s = do_switch_scr(sc, s);
2113 		splx(s);
2114 		DPRINTF(5, ("finishing previous switch\n"));
2115 		return EINVAL;
2116 	    } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2117 		/* let's assume screen switch has been completed. */
2118 		DPRINTF(5, ("reset WAIT_ACQ, "));
2119 		sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2120 		sc->switch_in_progress = 0;
2121 	    } else {
2122 		/*
2123 	 	 * We are in between screen release and acquisition, and
2124 		 * reached here via scgetc() or scrn_timer() which has
2125 		 * interrupted exchange_scr(). Don't do anything stupid.
2126 		 */
2127 		DPRINTF(5, ("waiting nothing, "));
2128 	    }
2129 	} else {
2130 	    /*
2131 	     * The controlling process is alive, but not responding...
2132 	     * It is either buggy or it may be just taking time.
2133 	     * The following code is a gross kludge to cope with this
2134 	     * problem for which there is no clean solution. XXX
2135 	     */
2136 	    if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2137 		switch (sc->switch_in_progress++) {
2138 		case 1:
2139 		    break;
2140 		case 2:
2141 		    DPRINTF(5, ("sending relsig again, "));
2142 		    signal_vt_rel(sc->cur_scp);
2143 		    break;
2144 		case 3:
2145 		    break;
2146 		case 4:
2147 		default:
2148 		    /*
2149 		     * Clear the flag and force the previous switch to finish,
2150 		     * but return now with error.
2151 		     */
2152 		    DPRINTF(5, ("force reset WAIT_REL, "));
2153 		    sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2154 		    s = do_switch_scr(sc, s);
2155 		    splx(s);
2156 		    DPRINTF(5, ("force finishing previous switch\n"));
2157 		    return EINVAL;
2158 		}
2159 	    } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2160 		switch (sc->switch_in_progress++) {
2161 		case 1:
2162 		    break;
2163 		case 2:
2164 		    DPRINTF(5, ("sending acqsig again, "));
2165 		    signal_vt_acq(sc->cur_scp);
2166 		    break;
2167 		case 3:
2168 		    break;
2169 		case 4:
2170 		default:
2171 		     /* clear the flag and finish the previous switch */
2172 		    DPRINTF(5, ("force reset WAIT_ACQ, "));
2173 		    sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2174 		    sc->switch_in_progress = 0;
2175 		    break;
2176 		}
2177 	    }
2178 	}
2179     }
2180 
2181     /*
2182      * Return error if an invalid argument is given, or vty switch
2183      * is still in progress.
2184      */
2185     if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2186 	|| sc->switch_in_progress) {
2187 	splx(s);
2188 	do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2189 	DPRINTF(5, ("error 1\n"));
2190 	return EINVAL;
2191     }
2192 
2193     /*
2194      * Don't allow switching away from the graphics mode vty
2195      * if the switch mode is VT_AUTO, unless the next vty is the same
2196      * as the current or the current vty has been closed (but showing).
2197      */
2198     tp = VIRTUAL_TTY(sc, sc->cur_scp->index);
2199     if ((sc->cur_scp->index != next_scr)
2200 	&& (tp->t_state & TS_ISOPEN)
2201 	&& (sc->cur_scp->smode.mode == VT_AUTO)
2202 	&& ISGRAPHSC(sc->cur_scp)) {
2203 	splx(s);
2204 	do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2205 	DPRINTF(5, ("error, graphics mode\n"));
2206 	return EINVAL;
2207     }
2208 
2209     /*
2210      * Is the wanted vty open? Don't allow switching to a closed vty.
2211      * Note that we always allow the user to switch to the kernel
2212      * console even if it is closed.
2213      */
2214     if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2215 	tp = VIRTUAL_TTY(sc, next_scr);
2216 	if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
2217 	    splx(s);
2218 	    do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2219 	    DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2220 	    return EINVAL;
2221 	}
2222     }
2223 
2224     /* this is the start of vty switching process... */
2225     ++sc->switch_in_progress;
2226     sc->delayed_next_scr = 0;
2227     sc->old_scp = sc->cur_scp;
2228     sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2229     if (sc->new_scp == sc->old_scp) {
2230 	sc->switch_in_progress = 0;
2231 	wakeup((caddr_t)&sc->new_scp->smode);
2232 	splx(s);
2233 	DPRINTF(5, ("switch done (new == old)\n"));
2234 	return 0;
2235     }
2236 
2237     /* has controlling process died? */
2238     vt_proc_alive(sc->old_scp);
2239     vt_proc_alive(sc->new_scp);
2240 
2241     /* wait for the controlling process to release the screen, if necessary */
2242     if (signal_vt_rel(sc->old_scp)) {
2243 	splx(s);
2244 	return 0;
2245     }
2246 
2247     /* go set up the new vty screen */
2248     splx(s);
2249     exchange_scr(sc);
2250     s = spltty();
2251 
2252     /* wake up processes waiting for this vty */
2253     wakeup((caddr_t)&sc->cur_scp->smode);
2254 
2255     /* wait for the controlling process to acknowledge, if necessary */
2256     if (signal_vt_acq(sc->cur_scp)) {
2257 	splx(s);
2258 	return 0;
2259     }
2260 
2261     sc->switch_in_progress = 0;
2262     if (sc->unit == sc_console_unit)
2263 	cons_unavail = FALSE;
2264     splx(s);
2265     DPRINTF(5, ("switch done\n"));
2266 
2267     return 0;
2268 }
2269 
2270 static int
2271 do_switch_scr(sc_softc_t *sc, int s)
2272 {
2273     vt_proc_alive(sc->new_scp);
2274 
2275     splx(s);
2276     exchange_scr(sc);
2277     s = spltty();
2278     /* sc->cur_scp == sc->new_scp */
2279     wakeup((caddr_t)&sc->cur_scp->smode);
2280 
2281     /* wait for the controlling process to acknowledge, if necessary */
2282     if (!signal_vt_acq(sc->cur_scp)) {
2283 	sc->switch_in_progress = 0;
2284 	if (sc->unit == sc_console_unit)
2285 	    cons_unavail = FALSE;
2286     }
2287 
2288     return s;
2289 }
2290 
2291 static int
2292 vt_proc_alive(scr_stat *scp)
2293 {
2294     if (scp->proc) {
2295 	if (scp->proc == pfind(scp->pid))
2296 	    return TRUE;
2297 	scp->proc = NULL;
2298 	scp->smode.mode = VT_AUTO;
2299 	DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2300     }
2301     return FALSE;
2302 }
2303 
2304 static int
2305 signal_vt_rel(scr_stat *scp)
2306 {
2307     if (scp->smode.mode != VT_PROCESS)
2308 	return FALSE;
2309     scp->status |= SWITCH_WAIT_REL;
2310     psignal(scp->proc, scp->smode.relsig);
2311     DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2312     return TRUE;
2313 }
2314 
2315 static int
2316 signal_vt_acq(scr_stat *scp)
2317 {
2318     if (scp->smode.mode != VT_PROCESS)
2319 	return FALSE;
2320     if (scp->sc->unit == sc_console_unit)
2321 	cons_unavail = TRUE;
2322     scp->status |= SWITCH_WAIT_ACQ;
2323     psignal(scp->proc, scp->smode.acqsig);
2324     DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2325     return TRUE;
2326 }
2327 
2328 static void
2329 exchange_scr(sc_softc_t *sc)
2330 {
2331     scr_stat *scp;
2332 
2333     /* save the current state of video and keyboard */
2334     move_crsr(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
2335     if (sc->old_scp->kbd_mode == K_XLATE)
2336 	save_kbd_state(sc->old_scp);
2337 
2338     /* set up the video for the new screen */
2339     scp = sc->cur_scp = sc->new_scp;
2340     if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
2341 	set_mode(scp);
2342     else
2343 	sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2344 		    (void *)sc->adp->va_window, FALSE);
2345     move_crsr(scp, scp->xpos, scp->ypos);
2346     if (!ISGRAPHSC(scp))
2347 	sc_set_cursor_image(scp);
2348 #ifndef SC_NO_PALETTE_LOADING
2349     if (ISGRAPHSC(sc->old_scp))
2350 	load_palette(sc->adp, sc->palette);
2351 #endif
2352     set_border(scp, scp->border);
2353 
2354     /* set up the keyboard for the new screen */
2355     if (sc->old_scp->kbd_mode != scp->kbd_mode)
2356 	kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2357     update_kbd_state(scp, scp->status, LOCK_MASK);
2358 
2359     mark_all(scp);
2360 }
2361 
2362 static void
2363 scan_esc(scr_stat *scp, u_char c)
2364 {
2365     static u_char ansi_col[16] =
2366 	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2367     sc_softc_t *sc;
2368     int i, n;
2369     int count;
2370 
2371     i = n = 0;
2372     sc = scp->sc;
2373     if (scp->term.esc == 1) {	/* seen ESC */
2374 	switch (c) {
2375 
2376 	case '7':   /* Save cursor position */
2377 	    scp->saved_xpos = scp->xpos;
2378 	    scp->saved_ypos = scp->ypos;
2379 	    break;
2380 
2381 	case '8':   /* Restore saved cursor position */
2382 	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2383 		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2384 	    break;
2385 
2386 	case '[':   /* Start ESC [ sequence */
2387 	    scp->term.esc = 2;
2388 	    scp->term.last_param = -1;
2389 	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2390 		scp->term.param[i] = 1;
2391 	    scp->term.num_param = 0;
2392 	    return;
2393 
2394 	case 'M':   /* Move cursor up 1 line, scroll if at top */
2395 	    if (scp->ypos > 0)
2396 		move_crsr(scp, scp->xpos, scp->ypos - 1);
2397 	    else {
2398 		sc_vtb_ins(&scp->vtb, 0, scp->xsize,
2399 			   sc->scr_map[0x20], scp->term.cur_color);
2400     		mark_all(scp);
2401 	    }
2402 	    break;
2403 #if notyet
2404 	case 'Q':
2405 	    scp->term.esc = 4;
2406 	    return;
2407 #endif
2408 	case 'c':   /* Clear screen & home */
2409 	    sc_clear_screen(scp);
2410 	    break;
2411 
2412 	case '(':   /* iso-2022: designate 94 character set to G0 */
2413 	    scp->term.esc = 5;
2414 	    return;
2415 	}
2416     }
2417     else if (scp->term.esc == 2) {	/* seen ESC [ */
2418 	if (c >= '0' && c <= '9') {
2419 	    if (scp->term.num_param < MAX_ESC_PAR) {
2420 	    if (scp->term.last_param != scp->term.num_param) {
2421 		scp->term.last_param = scp->term.num_param;
2422 		scp->term.param[scp->term.num_param] = 0;
2423 	    }
2424 	    else
2425 		scp->term.param[scp->term.num_param] *= 10;
2426 	    scp->term.param[scp->term.num_param] += c - '0';
2427 	    return;
2428 	    }
2429 	}
2430 	scp->term.num_param = scp->term.last_param + 1;
2431 	switch (c) {
2432 
2433 	case ';':
2434 	    if (scp->term.num_param < MAX_ESC_PAR)
2435 		return;
2436 	    break;
2437 
2438 	case '=':
2439 	    scp->term.esc = 3;
2440 	    scp->term.last_param = -1;
2441 	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2442 		scp->term.param[i] = 1;
2443 	    scp->term.num_param = 0;
2444 	    return;
2445 
2446 	case 'A':   /* up n rows */
2447 	    n = scp->term.param[0]; if (n < 1) n = 1;
2448 	    move_crsr(scp, scp->xpos, scp->ypos - n);
2449 	    break;
2450 
2451 	case 'B':   /* down n rows */
2452 	    n = scp->term.param[0]; if (n < 1) n = 1;
2453 	    move_crsr(scp, scp->xpos, scp->ypos + n);
2454 	    break;
2455 
2456 	case 'C':   /* right n columns */
2457 	    n = scp->term.param[0]; if (n < 1) n = 1;
2458 	    move_crsr(scp, scp->xpos + n, scp->ypos);
2459 	    break;
2460 
2461 	case 'D':   /* left n columns */
2462 	    n = scp->term.param[0]; if (n < 1) n = 1;
2463 	    move_crsr(scp, scp->xpos - n, scp->ypos);
2464 	    break;
2465 
2466 	case 'E':   /* cursor to start of line n lines down */
2467 	    n = scp->term.param[0]; if (n < 1) n = 1;
2468 	    move_crsr(scp, 0, scp->ypos + n);
2469 	    break;
2470 
2471 	case 'F':   /* cursor to start of line n lines up */
2472 	    n = scp->term.param[0]; if (n < 1) n = 1;
2473 	    move_crsr(scp, 0, scp->ypos - n);
2474 	    break;
2475 
2476 	case 'f':   /* Cursor move */
2477 	case 'H':
2478 	    if (scp->term.num_param == 0)
2479 		move_crsr(scp, 0, 0);
2480 	    else if (scp->term.num_param == 2)
2481 		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2482 	    break;
2483 
2484 	case 'J':   /* Clear all or part of display */
2485 	    if (scp->term.num_param == 0)
2486 		n = 0;
2487 	    else
2488 		n = scp->term.param[0];
2489 	    switch (n) {
2490 	    case 0: /* clear form cursor to end of display */
2491 		sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2492 			     scp->xsize * scp->ysize - scp->cursor_pos,
2493 			     sc->scr_map[0x20], scp->term.cur_color);
2494 		mark_for_update(scp, scp->cursor_pos);
2495     		mark_for_update(scp, scp->xsize * scp->ysize - 1);
2496 		sc_remove_cutmarking(scp);
2497 		break;
2498 	    case 1: /* clear from beginning of display to cursor */
2499 		sc_vtb_erase(&scp->vtb, 0, scp->cursor_pos,
2500 			     sc->scr_map[0x20], scp->term.cur_color);
2501 		mark_for_update(scp, 0);
2502 		mark_for_update(scp, scp->cursor_pos);
2503 		sc_remove_cutmarking(scp);
2504 		break;
2505 	    case 2: /* clear entire display */
2506 		sc_vtb_clear(&scp->vtb, sc->scr_map[0x20], scp->term.cur_color);
2507 		mark_all(scp);
2508 		sc_remove_cutmarking(scp);
2509 		break;
2510 	    }
2511 	    break;
2512 
2513 	case 'K':   /* Clear all or part of line */
2514 	    if (scp->term.num_param == 0)
2515 		n = 0;
2516 	    else
2517 		n = scp->term.param[0];
2518 	    switch (n) {
2519 	    case 0: /* clear form cursor to end of line */
2520 		sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2521 			     scp->xsize - scp->xpos,
2522 			     sc->scr_map[0x20], scp->term.cur_color);
2523     		mark_for_update(scp, scp->cursor_pos);
2524     		mark_for_update(scp, scp->cursor_pos +
2525 				scp->xsize - 1 - scp->xpos);
2526 		break;
2527 	    case 1: /* clear from beginning of line to cursor */
2528 		sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2529 			     scp->xpos + 1,
2530 			     sc->scr_map[0x20], scp->term.cur_color);
2531     		mark_for_update(scp, scp->ypos * scp->xsize);
2532     		mark_for_update(scp, scp->cursor_pos);
2533 		break;
2534 	    case 2: /* clear entire line */
2535 		sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2536 			     scp->xsize,
2537 			     sc->scr_map[0x20], scp->term.cur_color);
2538     		mark_for_update(scp, scp->ypos * scp->xsize);
2539     		mark_for_update(scp, (scp->ypos + 1) * scp->xsize - 1);
2540 		break;
2541 	    }
2542 	    break;
2543 
2544 	case 'L':   /* Insert n lines */
2545 	    n = scp->term.param[0]; if (n < 1) n = 1;
2546 	    if (n > scp->ysize - scp->ypos)
2547 		n = scp->ysize - scp->ypos;
2548 	    sc_vtb_ins(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2549 		       sc->scr_map[0x20], scp->term.cur_color);
2550 	    mark_for_update(scp, scp->ypos * scp->xsize);
2551 	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2552 	    break;
2553 
2554 	case 'M':   /* Delete n lines */
2555 	    n = scp->term.param[0]; if (n < 1) n = 1;
2556 	    if (n > scp->ysize - scp->ypos)
2557 		n = scp->ysize - scp->ypos;
2558 	    sc_vtb_delete(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2559 			  sc->scr_map[0x20], scp->term.cur_color);
2560 	    mark_for_update(scp, scp->ypos * scp->xsize);
2561 	    mark_for_update(scp, scp->xsize * scp->ysize - 1);
2562 	    break;
2563 
2564 	case 'P':   /* Delete n chars */
2565 	    n = scp->term.param[0]; if (n < 1) n = 1;
2566 	    if (n > scp->xsize - scp->xpos)
2567 		n = scp->xsize - scp->xpos;
2568 	    count = scp->xsize - (scp->xpos + n);
2569 	    sc_vtb_move(&scp->vtb, scp->cursor_pos + n, scp->cursor_pos, count);
2570 	    sc_vtb_erase(&scp->vtb, scp->cursor_pos + count, n,
2571 			 sc->scr_map[0x20], scp->term.cur_color);
2572 	    mark_for_update(scp, scp->cursor_pos);
2573 	    mark_for_update(scp, scp->cursor_pos + n + count - 1);
2574 	    break;
2575 
2576 	case '@':   /* Insert n chars */
2577 	    n = scp->term.param[0]; if (n < 1) n = 1;
2578 	    if (n > scp->xsize - scp->xpos)
2579 		n = scp->xsize - scp->xpos;
2580 	    count = scp->xsize - (scp->xpos + n);
2581 	    sc_vtb_move(&scp->vtb, scp->cursor_pos, scp->cursor_pos + n, count);
2582 	    sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2583 			 sc->scr_map[0x20], scp->term.cur_color);
2584 	    mark_for_update(scp, scp->cursor_pos);
2585 	    mark_for_update(scp, scp->cursor_pos + n + count - 1);
2586 	    break;
2587 
2588 	case 'S':   /* scroll up n lines */
2589 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2590 	    if (n > scp->ysize)
2591 		n = scp->ysize;
2592 	    sc_vtb_delete(&scp->vtb, 0, n * scp->xsize,
2593 			  sc->scr_map[0x20], scp->term.cur_color);
2594     	    mark_all(scp);
2595 	    break;
2596 
2597 	case 'T':   /* scroll down n lines */
2598 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2599 	    if (n > scp->ysize)
2600 		n = scp->ysize;
2601 	    sc_vtb_ins(&scp->vtb, 0, n * scp->xsize,
2602 		       sc->scr_map[0x20], scp->term.cur_color);
2603     	    mark_all(scp);
2604 	    break;
2605 
2606 	case 'X':   /* erase n characters in line */
2607 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2608 	    if (n > scp->xsize - scp->xpos)
2609 		n = scp->xsize - scp->xpos;
2610 	    sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2611 			 sc->scr_map[0x20], scp->term.cur_color);
2612 	    mark_for_update(scp, scp->cursor_pos);
2613 	    mark_for_update(scp, scp->cursor_pos + n - 1);
2614 	    break;
2615 
2616 	case 'Z':   /* move n tabs backwards */
2617 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2618 	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2619 		i -= 8*n;
2620 	    else
2621 		i -= 8*(n-1);
2622 	    if (i < 0)
2623 		i = 0;
2624 	    move_crsr(scp, i, scp->ypos);
2625 	    break;
2626 
2627 	case '`':   /* move cursor to column n */
2628 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2629 	    move_crsr(scp, n - 1, scp->ypos);
2630 	    break;
2631 
2632 	case 'a':   /* move cursor n columns to the right */
2633 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2634 	    move_crsr(scp, scp->xpos + n, scp->ypos);
2635 	    break;
2636 
2637 	case 'd':   /* move cursor to row n */
2638 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2639 	    move_crsr(scp, scp->xpos, n - 1);
2640 	    break;
2641 
2642 	case 'e':   /* move cursor n rows down */
2643 	    n = scp->term.param[0]; if (n < 1)  n = 1;
2644 	    move_crsr(scp, scp->xpos, scp->ypos + n);
2645 	    break;
2646 
2647 	case 'm':   /* change attribute */
2648 	    if (scp->term.num_param == 0) {
2649 		scp->term.attr_mask = NORMAL_ATTR;
2650 		scp->term.cur_attr =
2651 		    scp->term.cur_color = scp->term.std_color;
2652 		break;
2653 	    }
2654 	    for (i = 0; i < scp->term.num_param; i++) {
2655 		switch (n = scp->term.param[i]) {
2656 		case 0: /* back to normal */
2657 		    scp->term.attr_mask = NORMAL_ATTR;
2658 		    scp->term.cur_attr =
2659 			scp->term.cur_color = scp->term.std_color;
2660 		    break;
2661 		case 1: /* bold */
2662 		    scp->term.attr_mask |= BOLD_ATTR;
2663 		    scp->term.cur_attr = mask2attr(&scp->term);
2664 		    break;
2665 		case 4: /* underline */
2666 		    scp->term.attr_mask |= UNDERLINE_ATTR;
2667 		    scp->term.cur_attr = mask2attr(&scp->term);
2668 		    break;
2669 		case 5: /* blink */
2670 		    scp->term.attr_mask |= BLINK_ATTR;
2671 		    scp->term.cur_attr = mask2attr(&scp->term);
2672 		    break;
2673 		case 7: /* reverse video */
2674 		    scp->term.attr_mask |= REVERSE_ATTR;
2675 		    scp->term.cur_attr = mask2attr(&scp->term);
2676 		    break;
2677 		case 30: case 31: /* set fg color */
2678 		case 32: case 33: case 34:
2679 		case 35: case 36: case 37:
2680 		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2681 		    scp->term.cur_color =
2682 			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2683 		    scp->term.cur_attr = mask2attr(&scp->term);
2684 		    break;
2685 		case 40: case 41: /* set bg color */
2686 		case 42: case 43: case 44:
2687 		case 45: case 46: case 47:
2688 		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2689 		    scp->term.cur_color =
2690 			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2691 		    scp->term.cur_attr = mask2attr(&scp->term);
2692 		    break;
2693 		}
2694 	    }
2695 	    break;
2696 
2697 	case 's':   /* Save cursor position */
2698 	    scp->saved_xpos = scp->xpos;
2699 	    scp->saved_ypos = scp->ypos;
2700 	    break;
2701 
2702 	case 'u':   /* Restore saved cursor position */
2703 	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2704 		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2705 	    break;
2706 
2707 	case 'x':
2708 	    if (scp->term.num_param == 0)
2709 		n = 0;
2710 	    else
2711 		n = scp->term.param[0];
2712 	    switch (n) {
2713 	    case 0:     /* reset attributes */
2714 		scp->term.attr_mask = NORMAL_ATTR;
2715 		scp->term.cur_attr =
2716 		    scp->term.cur_color = scp->term.std_color =
2717 		    current_default->std_color;
2718 		scp->term.rev_color = current_default->rev_color;
2719 		break;
2720 	    case 1:     /* set ansi background */
2721 		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2722 		scp->term.cur_color = scp->term.std_color =
2723 		    (scp->term.std_color & 0x0F00) |
2724 		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2725 		scp->term.cur_attr = mask2attr(&scp->term);
2726 		break;
2727 	    case 2:     /* set ansi foreground */
2728 		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2729 		scp->term.cur_color = scp->term.std_color =
2730 		    (scp->term.std_color & 0xF000) |
2731 		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2732 		scp->term.cur_attr = mask2attr(&scp->term);
2733 		break;
2734 	    case 3:     /* set ansi attribute directly */
2735 		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2736 		scp->term.cur_color = scp->term.std_color =
2737 		    (scp->term.param[1]&0xFF)<<8;
2738 		scp->term.cur_attr = mask2attr(&scp->term);
2739 		break;
2740 	    case 5:     /* set ansi reverse video background */
2741 		scp->term.rev_color =
2742 		    (scp->term.rev_color & 0x0F00) |
2743 		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2744 		scp->term.cur_attr = mask2attr(&scp->term);
2745 		break;
2746 	    case 6:     /* set ansi reverse video foreground */
2747 		scp->term.rev_color =
2748 		    (scp->term.rev_color & 0xF000) |
2749 		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2750 		scp->term.cur_attr = mask2attr(&scp->term);
2751 		break;
2752 	    case 7:     /* set ansi reverse video directly */
2753 		scp->term.rev_color =
2754 		    (scp->term.param[1]&0xFF)<<8;
2755 		scp->term.cur_attr = mask2attr(&scp->term);
2756 		break;
2757 	    }
2758 	    break;
2759 
2760 	case 'z':   /* switch to (virtual) console n */
2761 	    if (scp->term.num_param == 1)
2762 		switch_scr(sc, scp->term.param[0]);
2763 	    break;
2764 	}
2765     }
2766     else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2767 	if (c >= '0' && c <= '9') {
2768 	    if (scp->term.num_param < MAX_ESC_PAR) {
2769 	    if (scp->term.last_param != scp->term.num_param) {
2770 		scp->term.last_param = scp->term.num_param;
2771 		scp->term.param[scp->term.num_param] = 0;
2772 	    }
2773 	    else
2774 		scp->term.param[scp->term.num_param] *= 10;
2775 	    scp->term.param[scp->term.num_param] += c - '0';
2776 	    return;
2777 	    }
2778 	}
2779 	scp->term.num_param = scp->term.last_param + 1;
2780 	switch (c) {
2781 
2782 	case ';':
2783 	    if (scp->term.num_param < MAX_ESC_PAR)
2784 		return;
2785 	    break;
2786 
2787 	case 'A':   /* set display border color */
2788 	    if (scp->term.num_param == 1) {
2789 		scp->border=scp->term.param[0] & 0xff;
2790 		if (scp == sc->cur_scp)
2791 		    set_border(scp, scp->border);
2792             }
2793 	    break;
2794 
2795 	case 'B':   /* set bell pitch and duration */
2796 	    if (scp->term.num_param == 2) {
2797 		scp->bell_pitch = scp->term.param[0];
2798 		scp->bell_duration = scp->term.param[1];
2799 	    }
2800 	    break;
2801 
2802 	case 'C':   /* set cursor type & shape */
2803 	    if (!ISGRAPHSC(sc->cur_scp))
2804 		remove_cursor_image(sc->cur_scp);
2805 	    if (scp->term.num_param == 1) {
2806 		if (scp->term.param[0] & 0x01)
2807 		    sc->flags |= SC_BLINK_CURSOR;
2808 		else
2809 		    sc->flags &= ~SC_BLINK_CURSOR;
2810 		if (scp->term.param[0] & 0x02)
2811 		    sc->flags |= SC_CHAR_CURSOR;
2812 		else
2813 		    sc->flags &= ~SC_CHAR_CURSOR;
2814 	    }
2815 	    else if (scp->term.num_param == 2) {
2816 		sc->cursor_base = scp->font_size
2817 					- (scp->term.param[1] & 0x1F) - 1;
2818 		sc->cursor_height = (scp->term.param[1] & 0x1F)
2819 					- (scp->term.param[0] & 0x1F) + 1;
2820 	    }
2821 	    /*
2822 	     * The cursor shape is global property; all virtual consoles
2823 	     * are affected. Update the cursor in the current console...
2824 	     */
2825 	    if (!ISGRAPHSC(sc->cur_scp)) {
2826 		i = spltty();
2827 		sc_set_cursor_image(sc->cur_scp);
2828 		draw_cursor_image(sc->cur_scp);
2829 		splx(i);
2830 	    }
2831 	    break;
2832 
2833 	case 'F':   /* set ansi foreground */
2834 	    if (scp->term.num_param == 1) {
2835 		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2836 		scp->term.cur_color = scp->term.std_color =
2837 		    (scp->term.std_color & 0xF000)
2838 		    | ((scp->term.param[0] & 0x0F) << 8);
2839 		scp->term.cur_attr = mask2attr(&scp->term);
2840 	    }
2841 	    break;
2842 
2843 	case 'G':   /* set ansi background */
2844 	    if (scp->term.num_param == 1) {
2845 		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2846 		scp->term.cur_color = scp->term.std_color =
2847 		    (scp->term.std_color & 0x0F00)
2848 		    | ((scp->term.param[0] & 0x0F) << 12);
2849 		scp->term.cur_attr = mask2attr(&scp->term);
2850 	    }
2851 	    break;
2852 
2853 	case 'H':   /* set ansi reverse video foreground */
2854 	    if (scp->term.num_param == 1) {
2855 		scp->term.rev_color =
2856 		    (scp->term.rev_color & 0xF000)
2857 		    | ((scp->term.param[0] & 0x0F) << 8);
2858 		scp->term.cur_attr = mask2attr(&scp->term);
2859 	    }
2860 	    break;
2861 
2862 	case 'I':   /* set ansi reverse video background */
2863 	    if (scp->term.num_param == 1) {
2864 		scp->term.rev_color =
2865 		    (scp->term.rev_color & 0x0F00)
2866 		    | ((scp->term.param[0] & 0x0F) << 12);
2867 		scp->term.cur_attr = mask2attr(&scp->term);
2868 	    }
2869 	    break;
2870 	}
2871     }
2872 #if notyet
2873     else if (scp->term.esc == 4) {	/* seen ESC Q */
2874 	/* to be filled */
2875     }
2876 #endif
2877     else if (scp->term.esc == 5) {	/* seen ESC ( */
2878 	switch (c) {
2879 	case 'B':   /* iso-2022: desginate ASCII into G0 */
2880 	    break;
2881 	/* other items to be filled */
2882 	default:
2883 	    break;
2884 	}
2885     }
2886     scp->term.esc = 0;
2887 }
2888 
2889 static void
2890 ansi_put(scr_stat *scp, u_char *buf, int len)
2891 {
2892     u_char *ptr = buf;
2893 
2894 #if NSPLASH > 0
2895     /* make screensaver happy */
2896     if (!sticky_splash && scp == scp->sc->cur_scp)
2897 	run_scrn_saver = FALSE;
2898 #endif
2899 
2900 outloop:
2901     scp->sc->write_in_progress++;
2902     if (scp->term.esc) {
2903 	scan_esc(scp, *ptr++);
2904 	len--;
2905     }
2906     else if (PRINTABLE(*ptr)) {     /* Print only printables */
2907 	vm_offset_t p;
2908 	u_char *map;
2909  	int cnt;
2910 	int attr;
2911 	int i;
2912 
2913 	p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
2914 	map = scp->sc->scr_map;
2915 	attr = scp->term.cur_attr;
2916 
2917 	cnt = (len <= scp->xsize - scp->xpos) ? len : (scp->xsize - scp->xpos);
2918 	i = cnt;
2919 	do {
2920 	    /*
2921 	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2922 	     * pointers in the following to volatile should have no effect,
2923 	     * but in fact speeds up this inner loop from 26 to 18 cycles
2924 	     * (+ cache misses) on i486's.
2925 	     */
2926 #define	UCVP(ucp)	((u_char volatile *)(ucp))
2927 	    p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)], attr);
2928 	    ++ptr;
2929 	    --i;
2930 	} while (i > 0 && PRINTABLE(*ptr));
2931 
2932 	len -= cnt - i;
2933 	mark_for_update(scp, scp->cursor_pos);
2934 	scp->cursor_pos += cnt - i;
2935 	mark_for_update(scp, scp->cursor_pos - 1);
2936 	scp->xpos += cnt - i;
2937 
2938 	if (scp->xpos >= scp->xsize) {
2939 	    scp->xpos = 0;
2940 	    scp->ypos++;
2941 	}
2942     }
2943     else  {
2944 	switch(*ptr) {
2945 	case 0x07:
2946 	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2947 	    break;
2948 
2949 	case 0x08:      /* non-destructive backspace */
2950 	    if (scp->cursor_pos > 0) {
2951 		mark_for_update(scp, scp->cursor_pos);
2952 		scp->cursor_pos--;
2953 		mark_for_update(scp, scp->cursor_pos);
2954 		if (scp->xpos > 0)
2955 		    scp->xpos--;
2956 		else {
2957 		    scp->xpos += scp->xsize - 1;
2958 		    scp->ypos--;
2959 		}
2960 	    }
2961 	    break;
2962 
2963 	case 0x09:  /* non-destructive tab */
2964 	    mark_for_update(scp, scp->cursor_pos);
2965 	    scp->cursor_pos += (8 - scp->xpos % 8u);
2966 	    mark_for_update(scp, scp->cursor_pos);
2967 	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2968 	        scp->xpos = 0;
2969 	        scp->ypos++;
2970 	    }
2971 	    break;
2972 
2973 	case 0x0a:  /* newline, same pos */
2974 	    mark_for_update(scp, scp->cursor_pos);
2975 	    scp->cursor_pos += scp->xsize;
2976 	    mark_for_update(scp, scp->cursor_pos);
2977 	    scp->ypos++;
2978 	    break;
2979 
2980 	case 0x0c:  /* form feed, clears screen */
2981 	    sc_clear_screen(scp);
2982 	    break;
2983 
2984 	case 0x0d:  /* return, return to pos 0 */
2985 	    mark_for_update(scp, scp->cursor_pos);
2986 	    scp->cursor_pos -= scp->xpos;
2987 	    mark_for_update(scp, scp->cursor_pos);
2988 	    scp->xpos = 0;
2989 	    break;
2990 
2991 	case 0x1b:  /* start escape sequence */
2992 	    scp->term.esc = 1;
2993 	    scp->term.num_param = 0;
2994 	    break;
2995 	}
2996 	ptr++; len--;
2997     }
2998     /* do we have to scroll ?? */
2999     if (scp->cursor_pos >= scp->ysize * scp->xsize) {
3000 	sc_remove_cutmarking(scp);
3001 #ifndef SC_NO_HISTORY
3002 	if (scp->history != NULL)
3003 	    sc_hist_save_one_line(scp, 0);
3004 #endif
3005 	sc_vtb_delete(&scp->vtb, 0, scp->xsize,
3006 		      scp->sc->scr_map[0x20], scp->term.cur_color);
3007 	scp->cursor_pos -= scp->xsize;
3008 	scp->ypos--;
3009     	mark_all(scp);
3010     }
3011     scp->sc->write_in_progress--;
3012     if (len)
3013 	goto outloop;
3014     if (scp->sc->delayed_next_scr)
3015 	switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3016 }
3017 
3018 static void
3019 draw_cursor_image(scr_stat *scp)
3020 {
3021     /* assert(scp == scp->sc->cur_scp); */
3022     ++scp->sc->videoio_in_progress;
3023     (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
3024 			      scp->sc->flags & SC_BLINK_CURSOR, TRUE,
3025 			      sc_inside_cutmark(scp, scp->cursor_pos));
3026     --scp->sc->videoio_in_progress;
3027 }
3028 
3029 static void
3030 remove_cursor_image(scr_stat *scp)
3031 {
3032     /* assert(scp == scp->sc->cur_scp); */
3033     ++scp->sc->videoio_in_progress;
3034     (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
3035 			      scp->sc->flags & SC_BLINK_CURSOR, FALSE,
3036 			      sc_inside_cutmark(scp, scp->cursor_oldpos));
3037     --scp->sc->videoio_in_progress;
3038 }
3039 
3040 static void
3041 update_cursor_image(scr_stat *scp)
3042 {
3043     int blink;
3044 
3045     if (scp->sc->flags & SC_CHAR_CURSOR) {
3046 	scp->cursor_base = scp->sc->cursor_base;
3047 	scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3048     } else {
3049 	scp->cursor_base = 0;
3050 	scp->cursor_height = scp->font_size;
3051     }
3052     blink = scp->sc->flags & SC_BLINK_CURSOR;
3053 
3054     /* assert(scp == scp->sc->cur_scp); */
3055     ++scp->sc->videoio_in_progress;
3056     (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
3057 			      sc_inside_cutmark(scp, scp->cursor_pos));
3058     (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
3059     (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
3060 			      sc_inside_cutmark(scp, scp->cursor_pos));
3061     --scp->sc->videoio_in_progress;
3062 }
3063 
3064 void
3065 sc_set_cursor_image(scr_stat *scp)
3066 {
3067     if (scp->sc->flags & SC_CHAR_CURSOR) {
3068 	scp->cursor_base = scp->sc->cursor_base;
3069 	scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3070     } else {
3071 	scp->cursor_base = 0;
3072 	scp->cursor_height = scp->font_size;
3073     }
3074 
3075     /* assert(scp == scp->sc->cur_scp); */
3076     ++scp->sc->videoio_in_progress;
3077     (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
3078 			     scp->sc->flags & SC_BLINK_CURSOR);
3079     --scp->sc->videoio_in_progress;
3080 }
3081 
3082 static void
3083 move_crsr(scr_stat *scp, int x, int y)
3084 {
3085     if (x < 0)
3086 	x = 0;
3087     if (y < 0)
3088 	y = 0;
3089     if (x >= scp->xsize)
3090 	x = scp->xsize-1;
3091     if (y >= scp->ysize)
3092 	y = scp->ysize-1;
3093     scp->xpos = x;
3094     scp->ypos = y;
3095     scp->cursor_pos = scp->ypos * scp->xsize + scp->xpos;
3096 }
3097 
3098 static void
3099 scinit(int unit, int flags)
3100 {
3101     /*
3102      * When syscons is being initialized as the kernel console, malloc()
3103      * is not yet functional, because various kernel structures has not been
3104      * fully initialized yet.  Therefore, we need to declare the following
3105      * static buffers for the console.  This is less than ideal,
3106      * but is necessry evil for the time being.  XXX
3107      */
3108     static scr_stat main_console;
3109     static dev_t main_devs[MAXCONS];
3110     static struct tty main_tty;
3111     static u_short sc_buffer[ROW*COL];	/* XXX */
3112 #ifndef SC_NO_FONT_LOADING
3113     static u_char font_8[256*8];
3114     static u_char font_14[256*14];
3115     static u_char font_16[256*16];
3116 #endif
3117 
3118     sc_softc_t *sc;
3119     scr_stat *scp;
3120     video_adapter_t *adp;
3121     int col;
3122     int row;
3123     int i;
3124 
3125     /* one time initialization */
3126     if (init_done == COLD) {
3127 	sc_get_bios_values(&bios_value);
3128 	current_default = &user_default;
3129 	/* kernel console attributes */
3130 	kernel_console.esc = 0;
3131 	kernel_console.attr_mask = NORMAL_ATTR;
3132 	kernel_console.cur_attr =
3133 	    kernel_console.cur_color = kernel_console.std_color =
3134 	    kernel_default.std_color;
3135 	kernel_console.rev_color = kernel_default.rev_color;
3136     }
3137     init_done = WARM;
3138 
3139     /*
3140      * Allocate resources.  Even if we are being called for the second
3141      * time, we must allocate them again, because they might have
3142      * disappeared...
3143      */
3144     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3145     adp = NULL;
3146     if (sc->adapter >= 0) {
3147 	vid_release(sc->adp, (void *)&sc->adapter);
3148 	adp = sc->adp;
3149 	sc->adp = NULL;
3150     }
3151     if (sc->keyboard >= 0) {
3152 	DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
3153 	i = kbd_release(sc->kbd, (void *)&sc->keyboard);
3154 	DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
3155 	if (sc->kbd != NULL) {
3156 	    DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, minor:%d, flags:0x%x\n",
3157 		unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3158 	}
3159 	sc->kbd = NULL;
3160     }
3161     sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
3162     sc->adp = vid_get_adapter(sc->adapter);
3163     /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
3164     sc->keyboard = kbd_allocate("*", unit, (void *)&sc->keyboard,
3165 				sckbdevent, sc);
3166     DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
3167     sc->kbd = kbd_get_keyboard(sc->keyboard);
3168     if (sc->kbd != NULL) {
3169 	DPRINTF(1, ("sc%d: kbd index:%d, minor:%d, flags:0x%x\n",
3170 		unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3171     }
3172 
3173     if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
3174 
3175 	sc->initial_mode = sc->adp->va_initial_mode;
3176 
3177 #ifndef SC_NO_FONT_LOADING
3178 	if (flags & SC_KERNEL_CONSOLE) {
3179 	    sc->font_8 = font_8;
3180 	    sc->font_14 = font_14;
3181 	    sc->font_16 = font_16;
3182 	} else if (sc->font_8 == NULL) {
3183 	    /* assert(sc_malloc) */
3184 	    sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK);
3185 	    sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK);
3186 	    sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK);
3187 	}
3188 #endif
3189 
3190 	/* extract the hardware cursor location and hide the cursor for now */
3191 	(*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
3192 	(*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
3193 
3194 	/* set up the first console */
3195 	sc->first_vty = unit*MAXCONS;
3196 	sc->vtys = MAXCONS;
3197 	if (flags & SC_KERNEL_CONSOLE) {
3198 	    sc->dev = main_devs;
3199 	    sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3200 	    sc->dev[0]->si_tty = &main_tty;
3201 	    ttyregister(&main_tty);
3202 	    scp = &main_console;
3203 	    init_scp(sc, sc->first_vty, scp);
3204 	    sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
3205 			(void *)sc_buffer, FALSE);
3206 	} else {
3207 	    /* assert(sc_malloc) */
3208 	    sc->dev = malloc(sizeof(dev_t)*sc->vtys, M_DEVBUF, M_WAITOK);
3209 	    bzero(sc->dev, sizeof(dev_t)*sc->vtys);
3210 	    sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3211 	    sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
3212 	    scp = alloc_scp(sc, sc->first_vty);
3213 	}
3214 	SC_STAT(sc->dev[0]) = scp;
3215 	sc->cur_scp = scp;
3216 
3217 	/* copy screen to temporary buffer */
3218 	sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3219 		    (void *)scp->sc->adp->va_window, FALSE);
3220 	if (ISTEXTSC(scp))
3221 	    sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
3222 
3223 	/* move cursors to the initial positions */
3224 	scp->mouse_pos = scp->mouse_oldpos = 0;
3225 	if (col >= scp->xsize)
3226 	    col = 0;
3227 	if (row >= scp->ysize)
3228 	    row = scp->ysize - 1;
3229 	scp->xpos = col;
3230 	scp->ypos = row;
3231 	scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
3232 	if (bios_value.cursor_end < scp->font_size)
3233 	    sc->cursor_base = scp->font_size - bios_value.cursor_end - 1;
3234 	else
3235 	    sc->cursor_base = 0;
3236 	i = bios_value.cursor_end - bios_value.cursor_start + 1;
3237 	sc->cursor_height = imin(i, scp->font_size);
3238 	if (!ISGRAPHSC(scp)) {
3239     	    sc_set_cursor_image(scp);
3240     	    draw_cursor_image(scp);
3241 	}
3242 
3243 	/* save font and palette */
3244 #ifndef SC_NO_FONT_LOADING
3245 	sc->fonts_loaded = 0;
3246 	if (ISFONTAVAIL(sc->adp->va_flags)) {
3247 #ifdef SC_DFLT_FONT
3248 	    bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
3249 	    bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
3250 	    bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
3251 	    sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
3252 	    if (scp->font_size < 14) {
3253 		copy_font(scp, LOAD, 8, sc->font_8);
3254 	    } else if (scp->font_size >= 16) {
3255 		copy_font(scp, LOAD, 16, sc->font_16);
3256 	    } else {
3257 		copy_font(scp, LOAD, 14, sc->font_14);
3258 	    }
3259 #else /* !SC_DFLT_FONT */
3260 	    if (scp->font_size < 14) {
3261 		copy_font(scp, SAVE, 8, sc->font_8);
3262 		sc->fonts_loaded = FONT_8;
3263 	    } else if (scp->font_size >= 16) {
3264 		copy_font(scp, SAVE, 16, sc->font_16);
3265 		sc->fonts_loaded = FONT_16;
3266 	    } else {
3267 		copy_font(scp, SAVE, 14, sc->font_14);
3268 		sc->fonts_loaded = FONT_14;
3269 	    }
3270 #endif /* SC_DFLT_FONT */
3271 	    /* FONT KLUDGE: always use the font page #0. XXX */
3272 	    (*vidsw[sc->adapter]->show_font)(sc->adp, 0);
3273 	}
3274 #endif /* !SC_NO_FONT_LOADING */
3275 
3276 #ifndef SC_NO_PALETTE_LOADING
3277 	save_palette(sc->adp, sc->palette);
3278 #endif
3279 
3280 #if NSPLASH > 0
3281 	if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
3282 	    /* we are ready to put up the splash image! */
3283 	    splash_init(sc->adp, scsplash_callback, sc);
3284 	    sc->flags |= SC_SPLASH_SCRN;
3285 	}
3286 #endif /* NSPLASH */
3287     }
3288 
3289     /* the rest is not necessary, if we have done it once */
3290     if (sc->flags & SC_INIT_DONE)
3291 	return;
3292 
3293     /* initialize mapscrn arrays to a one to one map */
3294     for (i = 0; i < sizeof(sc->scr_map); i++)
3295 	sc->scr_map[i] = sc->scr_rmap[i] = i;
3296 
3297     sc->flags |= SC_INIT_DONE;
3298 }
3299 
3300 #if __i386__
3301 static void
3302 scterm(int unit, int flags)
3303 {
3304     sc_softc_t *sc;
3305 
3306     sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3307     if (sc == NULL)
3308 	return;			/* shouldn't happen */
3309 
3310 #if NSPLASH > 0
3311     /* this console is no longer available for the splash screen */
3312     if (sc->flags & SC_SPLASH_SCRN) {
3313 	splash_term(sc->adp);
3314 	sc->flags &= ~SC_SPLASH_SCRN;
3315     }
3316 #endif /* NSPLASH */
3317 
3318 #if 0 /* XXX */
3319     /* move the hardware cursor to the upper-left corner */
3320     (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
3321 #endif
3322 
3323     /* release the keyboard and the video card */
3324     if (sc->keyboard >= 0)
3325 	kbd_release(sc->kbd, &sc->keyboard);
3326     if (sc->adapter >= 0)
3327 	vid_release(sc->adp, &sc->adapter);
3328 
3329     /* clear the structure */
3330     if (!(flags & SC_KERNEL_CONSOLE)) {
3331 	/* XXX: We need delete_dev() for this */
3332 	free(sc->dev, M_DEVBUF);
3333 #if 0
3334 	/* XXX: We need a ttyunregister for this */
3335 	free(sc->tty, M_DEVBUF);
3336 #endif
3337 #ifndef SC_NO_FONT_LOADING
3338 	free(sc->font_8, M_DEVBUF);
3339 	free(sc->font_14, M_DEVBUF);
3340 	free(sc->font_16, M_DEVBUF);
3341 #endif
3342 	/* XXX vtb, history */
3343     }
3344     bzero(sc, sizeof(*sc));
3345     sc->keyboard = -1;
3346     sc->adapter = -1;
3347 }
3348 #endif
3349 
3350 static void
3351 scshutdown(void *arg, int howto)
3352 {
3353     /* assert(sc_console != NULL) */
3354 
3355     sc_touch_scrn_saver();
3356     if (!cold && sc_console
3357 	&& sc_console->sc->cur_scp->smode.mode == VT_AUTO
3358 	&& sc_console->smode.mode == VT_AUTO)
3359 	switch_scr(sc_console->sc, sc_console->index);
3360     shutdown_in_progress = TRUE;
3361 }
3362 
3363 int
3364 sc_clean_up(scr_stat *scp)
3365 {
3366 #if NSPLASH > 0
3367     int error;
3368 #endif /* NSPLASH */
3369 
3370     sc_touch_scrn_saver();
3371 #if NSPLASH > 0
3372     if ((error = wait_scrn_saver_stop(scp->sc)))
3373 	return error;
3374 #endif /* NSPLASH */
3375     scp->status &= ~MOUSE_VISIBLE;
3376     sc_remove_cutmarking(scp);
3377     return 0;
3378 }
3379 
3380 void
3381 sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
3382 {
3383     sc_vtb_t new;
3384     sc_vtb_t old;
3385     int s;
3386 
3387     old = scp->vtb;
3388     sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
3389     if (!discard && (old.vtb_flags & VTB_VALID)) {
3390 	/* retain the current cursor position and buffer contants */
3391 	scp->cursor_oldpos = scp->cursor_pos;
3392 	/*
3393 	 * This works only if the old buffer has the same size as or larger
3394 	 * than the new one. XXX
3395 	 */
3396 	sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
3397 	scp->vtb = new;
3398     } else {
3399         /* clear the screen and move the text cursor to the top-left position */
3400 	s = splhigh();
3401 	scp->vtb = new;
3402 	sc_clear_screen(scp);
3403 	splx(s);
3404 	sc_vtb_destroy(&old);
3405     }
3406 
3407 #ifndef SC_NO_SYSMOUSE
3408     /* move the mouse cursor at the center of the screen */
3409     sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
3410 #endif
3411 }
3412 
3413 static scr_stat
3414 *alloc_scp(sc_softc_t *sc, int vty)
3415 {
3416     scr_stat *scp;
3417 
3418     /* assert(sc_malloc) */
3419 
3420     scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3421     init_scp(sc, vty, scp);
3422 
3423     sc_alloc_scr_buffer(scp, TRUE, TRUE);
3424 
3425 #ifndef SC_NO_SYSMOUSE
3426     if (ISMOUSEAVAIL(sc->adp->va_flags))
3427 	sc_alloc_cut_buffer(scp, TRUE);
3428 #endif
3429 
3430 #ifndef SC_NO_HISTORY
3431     sc_alloc_history_buffer(scp, 0, 0, TRUE);
3432 #endif
3433 
3434     sc_clear_screen(scp);
3435     return scp;
3436 }
3437 
3438 static void
3439 init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
3440 {
3441     video_info_t info;
3442 
3443     scp->index = vty;
3444     scp->sc = sc;
3445     scp->status = 0;
3446     scp->mode = sc->initial_mode;
3447     (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
3448     if (info.vi_flags & V_INFO_GRAPHICS) {
3449 	scp->status |= GRAPHICS_MODE;
3450 	scp->xpixel = info.vi_width;
3451 	scp->ypixel = info.vi_height;
3452 	scp->xsize = info.vi_width/8;
3453 	scp->ysize = info.vi_height/info.vi_cheight;
3454 	scp->font_size = FONT_NONE;
3455 	scp->font = NULL;
3456     } else {
3457 	scp->xsize = info.vi_width;
3458 	scp->ysize = info.vi_height;
3459 	scp->xpixel = scp->xsize*8;
3460 	scp->ypixel = scp->ysize*info.vi_cheight;
3461 	if (info.vi_cheight < 14) {
3462 	    scp->font_size = 8;
3463 #ifndef SC_NO_FONT_LOADING
3464 	    scp->font = sc->font_8;
3465 #else
3466 	    scp->font = NULL;
3467 #endif
3468 	} else if (info.vi_cheight >= 16) {
3469 	    scp->font_size = 16;
3470 #ifndef SC_NO_FONT_LOADING
3471 	    scp->font = sc->font_16;
3472 #else
3473 	    scp->font = NULL;
3474 #endif
3475 	} else {
3476 	    scp->font_size = 14;
3477 #ifndef SC_NO_FONT_LOADING
3478 	    scp->font = sc->font_14;
3479 #else
3480 	    scp->font = NULL;
3481 #endif
3482 	}
3483     }
3484     sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
3485     sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
3486     scp->xoff = scp->yoff = 0;
3487     scp->xpos = scp->ypos = 0;
3488     scp->saved_xpos = scp->saved_ypos = -1;
3489     scp->start = scp->xsize * scp->ysize - 1;
3490     scp->end = 0;
3491     scp->term.esc = 0;
3492     scp->term.attr_mask = NORMAL_ATTR;
3493     scp->term.cur_attr =
3494 	scp->term.cur_color = scp->term.std_color =
3495 	current_default->std_color;
3496     scp->term.rev_color = current_default->rev_color;
3497     scp->border = BG_BLACK;
3498     scp->cursor_base = sc->cursor_base;
3499     scp->cursor_height = imin(sc->cursor_height, scp->font_size);
3500     scp->mouse_xpos = scp->xoff*8 + scp->xsize*8/2;
3501     scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size/2;
3502     scp->mouse_cut_start = scp->xsize*scp->ysize;
3503     scp->mouse_cut_end = -1;
3504     scp->mouse_signal = 0;
3505     scp->mouse_pid = 0;
3506     scp->mouse_proc = NULL;
3507     scp->kbd_mode = K_XLATE;
3508     scp->bell_pitch = bios_value.bell_pitch;
3509     scp->bell_duration = BELL_DURATION;
3510     scp->status |= (bios_value.shift_state & NLKED);
3511     scp->status |= CURSOR_ENABLED;
3512     scp->pid = 0;
3513     scp->proc = NULL;
3514     scp->smode.mode = VT_AUTO;
3515     scp->history = NULL;
3516     scp->history_pos = 0;
3517     scp->history_size = 0;
3518 
3519     /* what if the following call fails... XXX */
3520     scp->rndr = sc_render_match(scp, scp->sc->adp,
3521 				scp->status & (GRAPHICS_MODE | PIXEL_MODE));
3522 }
3523 
3524 /*
3525  * scgetc(flags) - get character from keyboard.
3526  * If flags & SCGETC_CN, then avoid harmful side effects.
3527  * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3528  * return NOKEY if there is nothing there.
3529  */
3530 static u_int
3531 scgetc(sc_softc_t *sc, u_int flags)
3532 {
3533     scr_stat *scp;
3534 #ifndef SC_NO_HISTORY
3535     struct tty *tp;
3536 #endif
3537     u_int c;
3538     int this_scr;
3539     int f;
3540     int i;
3541 
3542     if (sc->kbd == NULL)
3543 	return NOKEY;
3544 
3545 next_code:
3546 #if 1
3547     /* I don't like this, but... XXX */
3548     if (flags & SCGETC_CN)
3549 	sccnupdate(sc->cur_scp);
3550 #endif
3551     scp = sc->cur_scp;
3552     /* first see if there is something in the keyboard port */
3553     for (;;) {
3554 	c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
3555 	if (c == ERRKEY) {
3556 	    if (!(flags & SCGETC_CN))
3557 		do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3558 	} else if (c == NOKEY)
3559 	    return c;
3560 	else
3561 	    break;
3562     }
3563 
3564     /* make screensaver happy */
3565     if (!(c & RELKEY))
3566 	sc_touch_scrn_saver();
3567 
3568 #ifdef __i386__
3569     if (!(flags & SCGETC_CN))
3570 	/* do the /dev/random device a favour */
3571 	add_keyboard_randomness(c);
3572 #endif
3573 
3574     if (scp->kbd_mode != K_XLATE)
3575 	return KEYCHAR(c);
3576 
3577     /* if scroll-lock pressed allow history browsing */
3578     if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
3579 
3580 	scp->status &= ~CURSOR_ENABLED;
3581 	remove_cursor_image(scp);
3582 
3583 #ifndef SC_NO_HISTORY
3584 	if (!(scp->status & BUFFER_SAVED)) {
3585 	    scp->status |= BUFFER_SAVED;
3586 	    sc_hist_save(scp);
3587 	}
3588 	switch (c) {
3589 	/* FIXME: key codes */
3590 	case SPCLKEY | FKEY | F(49):  /* home key */
3591 	    sc_remove_cutmarking(scp);
3592 	    sc_hist_home(scp);
3593 	    goto next_code;
3594 
3595 	case SPCLKEY | FKEY | F(57):  /* end key */
3596 	    sc_remove_cutmarking(scp);
3597 	    sc_hist_end(scp);
3598 	    goto next_code;
3599 
3600 	case SPCLKEY | FKEY | F(50):  /* up arrow key */
3601 	    sc_remove_cutmarking(scp);
3602 	    if (sc_hist_up_line(scp))
3603 		if (!(flags & SCGETC_CN))
3604 		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3605 	    goto next_code;
3606 
3607 	case SPCLKEY | FKEY | F(58):  /* down arrow key */
3608 	    sc_remove_cutmarking(scp);
3609 	    if (sc_hist_down_line(scp))
3610 		if (!(flags & SCGETC_CN))
3611 		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3612 	    goto next_code;
3613 
3614 	case SPCLKEY | FKEY | F(51):  /* page up key */
3615 	    sc_remove_cutmarking(scp);
3616 	    for (i=0; i<scp->ysize; i++)
3617 	    if (sc_hist_up_line(scp)) {
3618 		if (!(flags & SCGETC_CN))
3619 		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3620 		break;
3621 	    }
3622 	    goto next_code;
3623 
3624 	case SPCLKEY | FKEY | F(59):  /* page down key */
3625 	    sc_remove_cutmarking(scp);
3626 	    for (i=0; i<scp->ysize; i++)
3627 	    if (sc_hist_down_line(scp)) {
3628 		if (!(flags & SCGETC_CN))
3629 		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3630 		break;
3631 	    }
3632 	    goto next_code;
3633 	}
3634 #endif /* SC_NO_HISTORY */
3635     }
3636 
3637     /*
3638      * Process and consume special keys here.  Return a plain char code
3639      * or a char code with the META flag or a function key code.
3640      */
3641     if (c & RELKEY) {
3642 	/* key released */
3643 	/* goto next_code */
3644     } else {
3645 	/* key pressed */
3646 	if (c & SPCLKEY) {
3647 	    c &= ~SPCLKEY;
3648 	    switch (KEYCHAR(c)) {
3649 	    /* LOCKING KEYS */
3650 	    case NLK: case CLK: case ALK:
3651 		break;
3652 	    case SLK:
3653 		kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3654 		if (f & SLKED) {
3655 		    scp->status |= SLKED;
3656 		} else {
3657 		    if (scp->status & SLKED) {
3658 			scp->status &= ~SLKED;
3659 #ifndef SC_NO_HISTORY
3660 			if (scp->status & BUFFER_SAVED) {
3661 			    if (!sc_hist_restore(scp))
3662 				sc_remove_cutmarking(scp);
3663 			    scp->status &= ~BUFFER_SAVED;
3664 			    scp->status |= CURSOR_ENABLED;
3665 			    draw_cursor_image(scp);
3666 			}
3667 			tp = VIRTUAL_TTY(sc, scp->index);
3668 			if (tp->t_state & TS_ISOPEN)
3669 			    scstart(tp);
3670 #endif
3671 		    }
3672 		}
3673 		break;
3674 
3675 	    /* NON-LOCKING KEYS */
3676 	    case NOP:
3677 	    case LSH:  case RSH:  case LCTR: case RCTR:
3678 	    case LALT: case RALT: case ASH:  case META:
3679 		break;
3680 
3681 	    case BTAB:
3682 		if (!(sc->flags & SC_SCRN_BLANKED))
3683 		    return c;
3684 		break;
3685 
3686 	    case SPSC:
3687 #if NSPLASH > 0
3688 		/* force activatation/deactivation of the screen saver */
3689 		if (!(sc->flags & SC_SCRN_BLANKED)) {
3690 		    run_scrn_saver = TRUE;
3691 		    sc->scrn_time_stamp -= scrn_blank_time;
3692 		}
3693 		if (cold) {
3694 		    /*
3695 		     * While devices are being probed, the screen saver need
3696 		     * to be invoked explictly. XXX
3697 		     */
3698 		    if (sc->flags & SC_SCRN_BLANKED) {
3699 			scsplash_stick(FALSE);
3700 			stop_scrn_saver(sc, current_saver);
3701 		    } else {
3702 			if (!ISGRAPHSC(scp)) {
3703 			    scsplash_stick(TRUE);
3704 			    (*current_saver)(sc, TRUE);
3705 			}
3706 		    }
3707 		}
3708 #endif /* NSPLASH */
3709 		break;
3710 
3711 	    case RBT:
3712 #ifndef SC_DISABLE_REBOOT
3713 		shutdown_nice();
3714 #endif
3715 		break;
3716 
3717 #if NAPM > 0
3718 	    case SUSP:
3719 		apm_suspend(PMST_SUSPEND);
3720 		break;
3721 	    case STBY:
3722 		apm_suspend(PMST_STANDBY);
3723 		break;
3724 #else
3725 	    case SUSP:
3726 	    case STBY:
3727 		break;
3728 #endif
3729 
3730 	    case DBG:
3731 #ifndef SC_DISABLE_DDBKEY
3732 #ifdef DDB
3733 		if (debugger)
3734 		    break;
3735 		/* try to switch to the kernel console screen */
3736 		if (sc_console) {
3737 		    /*
3738 		     * TRY to make sure the screen saver is stopped,
3739 		     * and the screen is updated before switching to
3740 		     * the vty0.
3741 		     */
3742 		    scrn_timer(NULL);
3743 		    if (!cold
3744 			&& sc_console->sc->cur_scp->smode.mode == VT_AUTO
3745 			&& sc_console->smode.mode == VT_AUTO)
3746 			switch_scr(sc_console->sc, sc_console->index);
3747 		}
3748 		Debugger("manual escape to debugger");
3749 #else
3750 		printf("No debugger in kernel\n");
3751 #endif
3752 #else /* SC_DISABLE_DDBKEY */
3753 		/* do nothing */
3754 #endif /* SC_DISABLE_DDBKEY */
3755 		break;
3756 
3757 	    case NEXT:
3758 		this_scr = scp->index;
3759 		for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3760 			sc->first_vty + i != this_scr;
3761 			i = (i + 1)%sc->vtys) {
3762 		    struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3763 		    if (tp && tp->t_state & TS_ISOPEN) {
3764 			switch_scr(scp->sc, sc->first_vty + i);
3765 			break;
3766 		    }
3767 		}
3768 		break;
3769 
3770 	    case PREV:
3771 		this_scr = scp->index;
3772 		for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3773 			sc->first_vty + i != this_scr;
3774 			i = (i + sc->vtys - 1)%sc->vtys) {
3775 		    struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3776 		    if (tp && tp->t_state & TS_ISOPEN) {
3777 			switch_scr(scp->sc, sc->first_vty + i);
3778 			break;
3779 		    }
3780 		}
3781 		break;
3782 
3783 	    default:
3784 		if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3785 		    switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3786 		    break;
3787 		}
3788 		/* assert(c & FKEY) */
3789 		if (!(sc->flags & SC_SCRN_BLANKED))
3790 		    return c;
3791 		break;
3792 	    }
3793 	    /* goto next_code */
3794 	} else {
3795 	    /* regular keys (maybe MKEY is set) */
3796 	    if (!(sc->flags & SC_SCRN_BLANKED))
3797 		return c;
3798 	}
3799     }
3800 
3801     goto next_code;
3802 }
3803 
3804 int
3805 scmmap(dev_t dev, vm_offset_t offset, int nprot)
3806 {
3807     scr_stat *scp;
3808 
3809     if (SC_VTY(dev) == SC_MOUSE)
3810 	return -1;
3811     scp = SC_STAT(dev);
3812     if (scp != scp->sc->cur_scp)
3813 	return -1;
3814     return (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, offset, nprot);
3815 }
3816 
3817 /*
3818  * Calculate hardware attributes word using logical attributes mask and
3819  * hardware colors
3820  */
3821 
3822 static int
3823 mask2attr(struct term_stat *term)
3824 {
3825     int attr, mask = term->attr_mask;
3826 
3827     if (mask & REVERSE_ATTR) {
3828 	attr = ((mask & FOREGROUND_CHANGED) ?
3829 		((term->cur_color & 0xF000) >> 4) :
3830 		(term->rev_color & 0x0F00)) |
3831 	       ((mask & BACKGROUND_CHANGED) ?
3832 		((term->cur_color & 0x0F00) << 4) :
3833 		(term->rev_color & 0xF000));
3834     } else
3835 	attr = term->cur_color;
3836 
3837     /* XXX: underline mapping for Hercules adapter can be better */
3838     if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3839 	attr ^= 0x0800;
3840     if (mask & BLINK_ATTR)
3841 	attr ^= 0x8000;
3842 
3843     return attr;
3844 }
3845 
3846 static int
3847 save_kbd_state(scr_stat *scp)
3848 {
3849     int state;
3850     int error;
3851 
3852     error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3853     if (error == ENOIOCTL)
3854 	error = ENODEV;
3855     if (error == 0) {
3856 	scp->status &= ~LOCK_MASK;
3857 	scp->status |= state;
3858     }
3859     return error;
3860 }
3861 
3862 static int
3863 update_kbd_state(scr_stat *scp, int new_bits, int mask)
3864 {
3865     int state;
3866     int error;
3867 
3868     if (mask != LOCK_MASK) {
3869 	error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3870 	if (error == ENOIOCTL)
3871 	    error = ENODEV;
3872 	if (error)
3873 	    return error;
3874 	state &= ~mask;
3875 	state |= new_bits & mask;
3876     } else {
3877 	state = new_bits & LOCK_MASK;
3878     }
3879     error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3880     if (error == ENOIOCTL)
3881 	error = ENODEV;
3882     return error;
3883 }
3884 
3885 static int
3886 update_kbd_leds(scr_stat *scp, int which)
3887 {
3888     int error;
3889 
3890     which &= LOCK_MASK;
3891     error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3892     if (error == ENOIOCTL)
3893 	error = ENODEV;
3894     return error;
3895 }
3896 
3897 int
3898 set_mode(scr_stat *scp)
3899 {
3900     video_info_t info;
3901 
3902     /* reject unsupported mode */
3903     if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
3904 	return 1;
3905 
3906     /* if this vty is not currently showing, do nothing */
3907     if (scp != scp->sc->cur_scp)
3908 	return 0;
3909 
3910     /* setup video hardware for the given mode */
3911     (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3912     sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3913 		(void *)scp->sc->adp->va_window, FALSE);
3914 
3915 #ifndef SC_NO_FONT_LOADING
3916     /* load appropriate font */
3917     if (!(scp->status & GRAPHICS_MODE)) {
3918 	if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3919 	    if (scp->font_size < 14) {
3920 		if (scp->sc->fonts_loaded & FONT_8)
3921 		    copy_font(scp, LOAD, 8, scp->sc->font_8);
3922 	    } else if (scp->font_size >= 16) {
3923 		if (scp->sc->fonts_loaded & FONT_16)
3924 		    copy_font(scp, LOAD, 16, scp->sc->font_16);
3925 	    } else {
3926 		if (scp->sc->fonts_loaded & FONT_14)
3927 		    copy_font(scp, LOAD, 14, scp->sc->font_14);
3928 	    }
3929 	    /*
3930 	     * FONT KLUDGE:
3931 	     * This is an interim kludge to display correct font.
3932 	     * Always use the font page #0 on the video plane 2.
3933 	     * Somehow we cannot show the font in other font pages on
3934 	     * some video cards... XXX
3935 	     */
3936 	    (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, 0);
3937 	}
3938 	mark_all(scp);
3939     }
3940 #endif /* !SC_NO_FONT_LOADING */
3941 
3942     set_border(scp, scp->border);
3943     sc_set_cursor_image(scp);
3944 
3945     return 0;
3946 }
3947 
3948 void
3949 set_border(scr_stat *scp, int color)
3950 {
3951     ++scp->sc->videoio_in_progress;
3952     (*scp->rndr->draw_border)(scp, color);
3953     --scp->sc->videoio_in_progress;
3954 }
3955 
3956 #ifndef SC_NO_FONT_LOADING
3957 void
3958 copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
3959 {
3960     /*
3961      * FONT KLUDGE:
3962      * This is an interim kludge to display correct font.
3963      * Always use the font page #0 on the video plane 2.
3964      * Somehow we cannot show the font in other font pages on
3965      * some video cards... XXX
3966      */
3967     scp->sc->font_loading_in_progress = TRUE;
3968     if (operation == LOAD) {
3969 	(*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, font_size,
3970 					      buf, 0, 256);
3971     } else if (operation == SAVE) {
3972 	(*vidsw[scp->sc->adapter]->save_font)(scp->sc->adp, 0, font_size,
3973 					      buf, 0, 256);
3974     }
3975     scp->sc->font_loading_in_progress = FALSE;
3976 }
3977 #endif /* !SC_NO_FONT_LOADING */
3978 
3979 #ifndef SC_NO_SYSMOUSE
3980 struct tty
3981 *sc_get_mouse_tty(void)
3982 {
3983     return sc_mouse_tty;
3984 }
3985 #endif /* !SC_NO_SYSMOUSE */
3986 
3987 #ifndef SC_NO_CUTPASTE
3988 void
3989 sc_paste(scr_stat *scp, u_char *p, int count)
3990 {
3991     struct tty *tp;
3992     u_char *rmap;
3993 
3994     if (scp->status & MOUSE_VISIBLE) {
3995 	tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
3996 	if (!(tp->t_state & TS_ISOPEN))
3997 	    return;
3998 	rmap = scp->sc->scr_rmap;
3999 	for (; count > 0; --count)
4000 	    (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
4001     }
4002 }
4003 #endif /* SC_NO_CUTPASTE */
4004 
4005 static void
4006 do_bell(scr_stat *scp, int pitch, int duration)
4007 {
4008     if (cold || shutdown_in_progress)
4009 	return;
4010 
4011     if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL))
4012 	return;
4013 
4014     if (scp->sc->flags & SC_VISUAL_BELL) {
4015 	if (scp->sc->blink_in_progress)
4016 	    return;
4017 	scp->sc->blink_in_progress = 3;
4018 	if (scp != scp->sc->cur_scp)
4019 	    scp->sc->blink_in_progress += 2;
4020 	blink_screen(scp->sc->cur_scp);
4021     } else {
4022 	if (scp != scp->sc->cur_scp)
4023 	    pitch *= 2;
4024 	sysbeep(pitch, duration);
4025     }
4026 }
4027 
4028 static void
4029 blink_screen(void *arg)
4030 {
4031     scr_stat *scp = arg;
4032     struct tty *tp;
4033 
4034     if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
4035 	scp->sc->blink_in_progress = 0;
4036     	mark_all(scp);
4037 	tp = VIRTUAL_TTY(scp->sc, scp->index);
4038 	if (tp->t_state & TS_ISOPEN)
4039 	    scstart(tp);
4040 	if (scp->sc->delayed_next_scr)
4041 	    switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
4042     }
4043     else {
4044 	(*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
4045 			   scp->sc->blink_in_progress & 1);
4046 	scp->sc->blink_in_progress--;
4047 	timeout(blink_screen, scp, hz / 10);
4048     }
4049 }
4050 
4051 #endif /* NSC */
4052