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