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