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