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