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