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