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