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