syscons.c revision 48104
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.305 1999/05/31 11:25:13 phk 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, unit:%d, vty:%d\n",
489		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_delete(&scp->vtb, scp->cursor_pos, n,
2614			  sc->scr_map[0x20], scp->term.cur_color);
2615	    mark_for_update(scp, scp->cursor_pos);
2616	    mark_for_update(scp, scp->cursor_pos + n + count - 1);
2617	    break;
2618
2619	case '@':   /* Insert n chars */
2620	    n = scp->term.param[0]; if (n < 1) n = 1;
2621	    if (n > scp->xsize - scp->xpos)
2622		n = scp->xsize - scp->xpos;
2623	    count = scp->xsize - (scp->xpos + n);
2624	    sc_vtb_ins(&scp->vtb, scp->cursor_pos, n,
2625		       sc->scr_map[0x20], scp->term.cur_color);
2626	    mark_for_update(scp, scp->cursor_pos);
2627	    mark_for_update(scp, scp->cursor_pos + n + count - 1);
2628	    break;
2629
2630	case 'S':   /* scroll up n lines */
2631	    n = scp->term.param[0]; if (n < 1)  n = 1;
2632	    if (n > scp->ysize)
2633		n = scp->ysize;
2634	    sc_vtb_delete(&scp->vtb, 0, n * scp->xsize,
2635			  sc->scr_map[0x20], scp->term.cur_color);
2636    	    mark_all(scp);
2637	    break;
2638
2639	case 'T':   /* scroll down n lines */
2640	    n = scp->term.param[0]; if (n < 1)  n = 1;
2641	    if (n > scp->ysize)
2642		n = scp->ysize;
2643	    sc_vtb_ins(&scp->vtb, 0, n * scp->xsize,
2644		       sc->scr_map[0x20], scp->term.cur_color);
2645    	    mark_all(scp);
2646	    break;
2647
2648	case 'X':   /* erase n characters in line */
2649	    n = scp->term.param[0]; if (n < 1)  n = 1;
2650	    if (n > scp->xsize - scp->xpos)
2651		n = scp->xsize - scp->xpos;
2652	    sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2653			 sc->scr_map[0x20], scp->term.cur_color);
2654	    mark_for_update(scp, scp->cursor_pos);
2655	    mark_for_update(scp, scp->cursor_pos + n - 1);
2656	    break;
2657
2658	case 'Z':   /* move n tabs backwards */
2659	    n = scp->term.param[0]; if (n < 1)  n = 1;
2660	    if ((i = scp->xpos & 0xf8) == scp->xpos)
2661		i -= 8*n;
2662	    else
2663		i -= 8*(n-1);
2664	    if (i < 0)
2665		i = 0;
2666	    move_crsr(scp, i, scp->ypos);
2667	    break;
2668
2669	case '`':   /* move cursor to column n */
2670	    n = scp->term.param[0]; if (n < 1)  n = 1;
2671	    move_crsr(scp, n - 1, scp->ypos);
2672	    break;
2673
2674	case 'a':   /* move cursor n columns to the right */
2675	    n = scp->term.param[0]; if (n < 1)  n = 1;
2676	    move_crsr(scp, scp->xpos + n, scp->ypos);
2677	    break;
2678
2679	case 'd':   /* move cursor to row n */
2680	    n = scp->term.param[0]; if (n < 1)  n = 1;
2681	    move_crsr(scp, scp->xpos, n - 1);
2682	    break;
2683
2684	case 'e':   /* move cursor n rows down */
2685	    n = scp->term.param[0]; if (n < 1)  n = 1;
2686	    move_crsr(scp, scp->xpos, scp->ypos + n);
2687	    break;
2688
2689	case 'm':   /* change attribute */
2690	    if (scp->term.num_param == 0) {
2691		scp->term.attr_mask = NORMAL_ATTR;
2692		scp->term.cur_attr =
2693		    scp->term.cur_color = scp->term.std_color;
2694		break;
2695	    }
2696	    for (i = 0; i < scp->term.num_param; i++) {
2697		switch (n = scp->term.param[i]) {
2698		case 0: /* back to normal */
2699		    scp->term.attr_mask = NORMAL_ATTR;
2700		    scp->term.cur_attr =
2701			scp->term.cur_color = scp->term.std_color;
2702		    break;
2703		case 1: /* bold */
2704		    scp->term.attr_mask |= BOLD_ATTR;
2705		    scp->term.cur_attr = mask2attr(&scp->term);
2706		    break;
2707		case 4: /* underline */
2708		    scp->term.attr_mask |= UNDERLINE_ATTR;
2709		    scp->term.cur_attr = mask2attr(&scp->term);
2710		    break;
2711		case 5: /* blink */
2712		    scp->term.attr_mask |= BLINK_ATTR;
2713		    scp->term.cur_attr = mask2attr(&scp->term);
2714		    break;
2715		case 7: /* reverse video */
2716		    scp->term.attr_mask |= REVERSE_ATTR;
2717		    scp->term.cur_attr = mask2attr(&scp->term);
2718		    break;
2719		case 30: case 31: /* set fg color */
2720		case 32: case 33: case 34:
2721		case 35: case 36: case 37:
2722		    scp->term.attr_mask |= FOREGROUND_CHANGED;
2723		    scp->term.cur_color =
2724			(scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2725		    scp->term.cur_attr = mask2attr(&scp->term);
2726		    break;
2727		case 40: case 41: /* set bg color */
2728		case 42: case 43: case 44:
2729		case 45: case 46: case 47:
2730		    scp->term.attr_mask |= BACKGROUND_CHANGED;
2731		    scp->term.cur_color =
2732			(scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2733		    scp->term.cur_attr = mask2attr(&scp->term);
2734		    break;
2735		}
2736	    }
2737	    break;
2738
2739	case 's':   /* Save cursor position */
2740	    scp->saved_xpos = scp->xpos;
2741	    scp->saved_ypos = scp->ypos;
2742	    break;
2743
2744	case 'u':   /* Restore saved cursor position */
2745	    if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2746		move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2747	    break;
2748
2749	case 'x':
2750	    if (scp->term.num_param == 0)
2751		n = 0;
2752	    else
2753		n = scp->term.param[0];
2754	    switch (n) {
2755	    case 0:     /* reset attributes */
2756		scp->term.attr_mask = NORMAL_ATTR;
2757		scp->term.cur_attr =
2758		    scp->term.cur_color = scp->term.std_color =
2759		    current_default->std_color;
2760		scp->term.rev_color = current_default->rev_color;
2761		break;
2762	    case 1:     /* set ansi background */
2763		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2764		scp->term.cur_color = scp->term.std_color =
2765		    (scp->term.std_color & 0x0F00) |
2766		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2767		scp->term.cur_attr = mask2attr(&scp->term);
2768		break;
2769	    case 2:     /* set ansi foreground */
2770		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2771		scp->term.cur_color = scp->term.std_color =
2772		    (scp->term.std_color & 0xF000) |
2773		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2774		scp->term.cur_attr = mask2attr(&scp->term);
2775		break;
2776	    case 3:     /* set ansi attribute directly */
2777		scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2778		scp->term.cur_color = scp->term.std_color =
2779		    (scp->term.param[1]&0xFF)<<8;
2780		scp->term.cur_attr = mask2attr(&scp->term);
2781		break;
2782	    case 5:     /* set ansi reverse video background */
2783		scp->term.rev_color =
2784		    (scp->term.rev_color & 0x0F00) |
2785		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
2786		scp->term.cur_attr = mask2attr(&scp->term);
2787		break;
2788	    case 6:     /* set ansi reverse video foreground */
2789		scp->term.rev_color =
2790		    (scp->term.rev_color & 0xF000) |
2791		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
2792		scp->term.cur_attr = mask2attr(&scp->term);
2793		break;
2794	    case 7:     /* set ansi reverse video directly */
2795		scp->term.rev_color =
2796		    (scp->term.param[1]&0xFF)<<8;
2797		scp->term.cur_attr = mask2attr(&scp->term);
2798		break;
2799	    }
2800	    break;
2801
2802	case 'z':   /* switch to (virtual) console n */
2803	    if (scp->term.num_param == 1)
2804		switch_scr(sc, scp->term.param[0]);
2805	    break;
2806	}
2807    }
2808    else if (scp->term.esc == 3) {	/* seen ESC [0-9]+ = */
2809	if (c >= '0' && c <= '9') {
2810	    if (scp->term.num_param < MAX_ESC_PAR) {
2811	    if (scp->term.last_param != scp->term.num_param) {
2812		scp->term.last_param = scp->term.num_param;
2813		scp->term.param[scp->term.num_param] = 0;
2814	    }
2815	    else
2816		scp->term.param[scp->term.num_param] *= 10;
2817	    scp->term.param[scp->term.num_param] += c - '0';
2818	    return;
2819	    }
2820	}
2821	scp->term.num_param = scp->term.last_param + 1;
2822	switch (c) {
2823
2824	case ';':
2825	    if (scp->term.num_param < MAX_ESC_PAR)
2826		return;
2827	    break;
2828
2829	case 'A':   /* set display border color */
2830	    if (scp->term.num_param == 1) {
2831		scp->border=scp->term.param[0] & 0xff;
2832		if (scp == sc->cur_scp)
2833		    set_border(scp, scp->border);
2834            }
2835	    break;
2836
2837	case 'B':   /* set bell pitch and duration */
2838	    if (scp->term.num_param == 2) {
2839		scp->bell_pitch = scp->term.param[0];
2840		scp->bell_duration = scp->term.param[1];
2841	    }
2842	    break;
2843
2844	case 'C':   /* set cursor type & shape */
2845	    if (!ISGRAPHSC(sc->cur_scp))
2846		remove_cursor_image(sc->cur_scp);
2847	    if (scp->term.num_param == 1) {
2848		if (scp->term.param[0] & 0x01)
2849		    sc->flags |= SC_BLINK_CURSOR;
2850		else
2851		    sc->flags &= ~SC_BLINK_CURSOR;
2852		if (scp->term.param[0] & 0x02)
2853		    sc->flags |= SC_CHAR_CURSOR;
2854		else
2855		    sc->flags &= ~SC_CHAR_CURSOR;
2856	    }
2857	    else if (scp->term.num_param == 2) {
2858		sc->cursor_base = scp->font_size
2859					- (scp->term.param[1] & 0x1F) - 1;
2860		sc->cursor_height = (scp->term.param[1] & 0x1F)
2861					- (scp->term.param[0] & 0x1F) + 1;
2862	    }
2863	    /*
2864	     * The cursor shape is global property; all virtual consoles
2865	     * are affected. Update the cursor in the current console...
2866	     */
2867	    if (!ISGRAPHSC(sc->cur_scp)) {
2868		i = spltty();
2869		sc_set_cursor_image(sc->cur_scp);
2870		draw_cursor_image(sc->cur_scp);
2871		splx(i);
2872	    }
2873	    break;
2874
2875	case 'F':   /* set ansi foreground */
2876	    if (scp->term.num_param == 1) {
2877		scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2878		scp->term.cur_color = scp->term.std_color =
2879		    (scp->term.std_color & 0xF000)
2880		    | ((scp->term.param[0] & 0x0F) << 8);
2881		scp->term.cur_attr = mask2attr(&scp->term);
2882	    }
2883	    break;
2884
2885	case 'G':   /* set ansi background */
2886	    if (scp->term.num_param == 1) {
2887		scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2888		scp->term.cur_color = scp->term.std_color =
2889		    (scp->term.std_color & 0x0F00)
2890		    | ((scp->term.param[0] & 0x0F) << 12);
2891		scp->term.cur_attr = mask2attr(&scp->term);
2892	    }
2893	    break;
2894
2895	case 'H':   /* set ansi reverse video foreground */
2896	    if (scp->term.num_param == 1) {
2897		scp->term.rev_color =
2898		    (scp->term.rev_color & 0xF000)
2899		    | ((scp->term.param[0] & 0x0F) << 8);
2900		scp->term.cur_attr = mask2attr(&scp->term);
2901	    }
2902	    break;
2903
2904	case 'I':   /* set ansi reverse video background */
2905	    if (scp->term.num_param == 1) {
2906		scp->term.rev_color =
2907		    (scp->term.rev_color & 0x0F00)
2908		    | ((scp->term.param[0] & 0x0F) << 12);
2909		scp->term.cur_attr = mask2attr(&scp->term);
2910	    }
2911	    break;
2912	}
2913    }
2914#if notyet
2915    else if (scp->term.esc == 4) {	/* seen ESC Q */
2916	/* to be filled */
2917    }
2918#endif
2919    else if (scp->term.esc == 5) {	/* seen ESC ( */
2920	switch (c) {
2921	case 'B':   /* iso-2022: desginate ASCII into G0 */
2922	    break;
2923	/* other items to be filled */
2924	default:
2925	    break;
2926	}
2927    }
2928    scp->term.esc = 0;
2929}
2930
2931static void
2932ansi_put(scr_stat *scp, u_char *buf, int len)
2933{
2934    u_char *ptr = buf;
2935
2936    /* make screensaver happy */
2937    if (!sticky_splash && scp == scp->sc->cur_scp)
2938	run_scrn_saver = FALSE;
2939
2940outloop:
2941    scp->sc->write_in_progress++;
2942    if (scp->term.esc) {
2943	scan_esc(scp, *ptr++);
2944	len--;
2945    }
2946    else if (PRINTABLE(*ptr)) {     /* Print only printables */
2947	vm_offset_t p;
2948	u_char *map;
2949 	int cnt;
2950	int attr;
2951	int i;
2952
2953	p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
2954	map = scp->sc->scr_map;
2955	attr = scp->term.cur_attr;
2956
2957	cnt = (len <= scp->xsize - scp->xpos) ? len : (scp->xsize - scp->xpos);
2958	i = cnt;
2959	do {
2960	    /*
2961	     * gcc-2.6.3 generates poor (un)sign extension code.  Casting the
2962	     * pointers in the following to volatile should have no effect,
2963	     * but in fact speeds up this inner loop from 26 to 18 cycles
2964	     * (+ cache misses) on i486's.
2965	     */
2966#define	UCVP(ucp)	((u_char volatile *)(ucp))
2967	    p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)], attr);
2968	    ++ptr;
2969	    --i;
2970	} while (i > 0 && PRINTABLE(*ptr));
2971
2972	len -= cnt - i;
2973	mark_for_update(scp, scp->cursor_pos);
2974	scp->cursor_pos += cnt - i;
2975	mark_for_update(scp, scp->cursor_pos - 1);
2976	scp->xpos += cnt - i;
2977
2978	if (scp->xpos >= scp->xsize) {
2979	    scp->xpos = 0;
2980	    scp->ypos++;
2981	}
2982    }
2983    else  {
2984	switch(*ptr) {
2985	case 0x07:
2986	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
2987	    break;
2988
2989	case 0x08:      /* non-destructive backspace */
2990	    if (scp->cursor_pos > 0) {
2991		mark_for_update(scp, scp->cursor_pos);
2992		scp->cursor_pos--;
2993		mark_for_update(scp, scp->cursor_pos);
2994		if (scp->xpos > 0)
2995		    scp->xpos--;
2996		else {
2997		    scp->xpos += scp->xsize - 1;
2998		    scp->ypos--;
2999		}
3000	    }
3001	    break;
3002
3003	case 0x09:  /* non-destructive tab */
3004	    mark_for_update(scp, scp->cursor_pos);
3005	    scp->cursor_pos += (8 - scp->xpos % 8u);
3006	    mark_for_update(scp, scp->cursor_pos);
3007	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
3008	        scp->xpos = 0;
3009	        scp->ypos++;
3010	    }
3011	    break;
3012
3013	case 0x0a:  /* newline, same pos */
3014	    mark_for_update(scp, scp->cursor_pos);
3015	    scp->cursor_pos += scp->xsize;
3016	    mark_for_update(scp, scp->cursor_pos);
3017	    scp->ypos++;
3018	    break;
3019
3020	case 0x0c:  /* form feed, clears screen */
3021	    sc_clear_screen(scp);
3022	    break;
3023
3024	case 0x0d:  /* return, return to pos 0 */
3025	    mark_for_update(scp, scp->cursor_pos);
3026	    scp->cursor_pos -= scp->xpos;
3027	    mark_for_update(scp, scp->cursor_pos);
3028	    scp->xpos = 0;
3029	    break;
3030
3031	case 0x1b:  /* start escape sequence */
3032	    scp->term.esc = 1;
3033	    scp->term.num_param = 0;
3034	    break;
3035	}
3036	ptr++; len--;
3037    }
3038    /* do we have to scroll ?? */
3039    if (scp->cursor_pos >= scp->ysize * scp->xsize) {
3040	sc_remove_cutmarking(scp);
3041#ifndef SC_NO_HISTORY
3042	if (scp->history != NULL)
3043	    sc_hist_save_one_line(scp, 0);
3044#endif
3045	sc_vtb_delete(&scp->vtb, 0, scp->xsize,
3046		      scp->sc->scr_map[0x20], scp->term.cur_color);
3047	scp->cursor_pos -= scp->xsize;
3048	scp->ypos--;
3049    	mark_all(scp);
3050    }
3051    scp->sc->write_in_progress--;
3052    if (len)
3053	goto outloop;
3054    if (scp->sc->delayed_next_scr)
3055	switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3056}
3057
3058static void
3059draw_cursor_image(scr_stat *scp)
3060{
3061    /* assert(scp == scp->sc->cur_scp); */
3062    ++scp->sc->videoio_in_progress;
3063    (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
3064			      scp->sc->flags & SC_BLINK_CURSOR, TRUE,
3065			      sc_inside_cutmark(scp, scp->cursor_pos));
3066    --scp->sc->videoio_in_progress;
3067}
3068
3069static void
3070remove_cursor_image(scr_stat *scp)
3071{
3072    /* assert(scp == scp->sc->cur_scp); */
3073    ++scp->sc->videoio_in_progress;
3074    (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
3075			      scp->sc->flags & SC_BLINK_CURSOR, FALSE,
3076			      sc_inside_cutmark(scp, scp->cursor_oldpos));
3077    --scp->sc->videoio_in_progress;
3078}
3079
3080static void
3081update_cursor_image(scr_stat *scp)
3082{
3083    int blink;
3084
3085    if (scp->sc->flags & SC_CHAR_CURSOR) {
3086	scp->cursor_base = scp->sc->cursor_base;
3087	scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3088    } else {
3089	scp->cursor_base = 0;
3090	scp->cursor_height = scp->font_size;
3091    }
3092    blink = scp->sc->flags & SC_BLINK_CURSOR;
3093
3094    /* assert(scp == scp->sc->cur_scp); */
3095    ++scp->sc->videoio_in_progress;
3096    (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
3097			      sc_inside_cutmark(scp, scp->cursor_pos));
3098    (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
3099    (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
3100			      sc_inside_cutmark(scp, scp->cursor_pos));
3101    --scp->sc->videoio_in_progress;
3102}
3103
3104void
3105sc_set_cursor_image(scr_stat *scp)
3106{
3107    if (scp->sc->flags & SC_CHAR_CURSOR) {
3108	scp->cursor_base = scp->sc->cursor_base;
3109	scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3110    } else {
3111	scp->cursor_base = 0;
3112	scp->cursor_height = scp->font_size;
3113    }
3114
3115    /* assert(scp == scp->sc->cur_scp); */
3116    ++scp->sc->videoio_in_progress;
3117    (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
3118			     scp->sc->flags & SC_BLINK_CURSOR);
3119    --scp->sc->videoio_in_progress;
3120}
3121
3122static void
3123move_crsr(scr_stat *scp, int x, int y)
3124{
3125    if (x < 0)
3126	x = 0;
3127    if (y < 0)
3128	y = 0;
3129    if (x >= scp->xsize)
3130	x = scp->xsize-1;
3131    if (y >= scp->ysize)
3132	y = scp->ysize-1;
3133    scp->xpos = x;
3134    scp->ypos = y;
3135    scp->cursor_pos = scp->ypos * scp->xsize + scp->xpos;
3136}
3137
3138static void
3139scinit(int unit, int flags)
3140{
3141    /*
3142     * When syscons is being initialized as the kernel console, malloc()
3143     * is not yet functional, because various kernel structures has not been
3144     * fully initialized yet.  Therefore, we need to declare the following
3145     * static buffers for the console.  This is less than ideal,
3146     * but is necessry evil for the time being.  XXX
3147     */
3148    static scr_stat main_console;
3149    static scr_stat *main_vtys[MAXCONS];
3150    static struct tty main_tty[MAXCONS];
3151    static u_short sc_buffer[ROW*COL];	/* XXX */
3152#ifdef DEVFS
3153    static void	*main_devfs_token[MAXCONS];
3154#endif
3155#ifndef SC_NO_FONT_LOADING
3156    static u_char font_8[256*8];
3157    static u_char font_14[256*14];
3158    static u_char font_16[256*16];
3159#endif
3160
3161    sc_softc_t *sc;
3162    scr_stat *scp;
3163    video_adapter_t *adp;
3164    int col;
3165    int row;
3166    int i;
3167
3168    /* one time initialization */
3169    if (init_done == COLD) {
3170	sc_get_bios_values(&bios_value);
3171	current_default = &user_default;
3172	/* kernel console attributes */
3173	kernel_console.esc = 0;
3174	kernel_console.attr_mask = NORMAL_ATTR;
3175	kernel_console.cur_attr =
3176	    kernel_console.cur_color = kernel_console.std_color =
3177	    kernel_default.std_color;
3178	kernel_console.rev_color = kernel_default.rev_color;
3179    }
3180    init_done = WARM;
3181
3182    /*
3183     * Allocate resources.  Even if we are being called for the second
3184     * time, we must allocate them again, because they might have
3185     * disappeared...
3186     */
3187    sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3188    adp = NULL;
3189    if (sc->adapter >= 0) {
3190	vid_release(sc->adp, (void *)&sc->adapter);
3191	adp = sc->adp;
3192	sc->adp = NULL;
3193    }
3194    if (sc->keyboard >= 0) {
3195	DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
3196	i = kbd_release(sc->kbd, (void *)&sc->keyboard);
3197	DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
3198	if (sc->kbd != NULL) {
3199	    DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, minor:%d, flags:0x%x\n",
3200		unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3201	}
3202	sc->kbd = NULL;
3203    }
3204    sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
3205    sc->adp = vid_get_adapter(sc->adapter);
3206    /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
3207    sc->keyboard = kbd_allocate("*", unit, (void *)&sc->keyboard,
3208				sckbdevent, sc);
3209    DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
3210    sc->kbd = kbd_get_keyboard(sc->keyboard);
3211    if (sc->kbd != NULL) {
3212	DPRINTF(1, ("sc%d: kbd index:%d, minor:%d, flags:0x%x\n",
3213		unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3214    }
3215
3216    if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
3217
3218	sc->initial_mode = sc->adp->va_initial_mode;
3219
3220#ifndef SC_NO_FONT_LOADING
3221	if (flags & SC_KERNEL_CONSOLE) {
3222	    sc->font_8 = font_8;
3223	    sc->font_14 = font_14;
3224	    sc->font_16 = font_16;
3225	} else if (sc->font_8 == NULL) {
3226	    /* assert(sc_malloc) */
3227	    sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK);
3228	    sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK);
3229	    sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK);
3230	}
3231#endif
3232
3233	/* extract the hardware cursor location and hide the cursor for now */
3234	(*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
3235	(*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
3236
3237	/* set up the first console */
3238	sc->first_vty = unit*MAXCONS;
3239	if (flags & SC_KERNEL_CONSOLE) {
3240	    sc->vtys = sizeof(main_vtys)/sizeof(main_vtys[0]);
3241	    sc->tty = main_tty;
3242#ifdef DEVFS
3243	    sc->devfs_token = main_devfs_token;
3244#endif
3245	    sc->console = main_vtys;
3246	    scp = main_vtys[0] = &main_console;
3247	    init_scp(sc, sc->first_vty, scp);
3248	    sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
3249			(void *)sc_buffer, FALSE);
3250	} else {
3251	    /* assert(sc_malloc) */
3252	    sc->vtys = MAXCONS;
3253	    sc->tty = malloc(sizeof(struct tty)*MAXCONS, M_DEVBUF, M_WAITOK);
3254	    bzero(sc->tty, sizeof(struct tty)*MAXCONS);
3255#ifdef DEVFS
3256	    sc->devfs_token = malloc(sizeof(void *)*MAXCONS,
3257				     M_DEVBUF, M_WAITOK);
3258#endif
3259	    sc->console = malloc(sizeof(struct scr_stat *)*MAXCONS,
3260				 M_DEVBUF, M_WAITOK);
3261	    scp = sc->console[0] = alloc_scp(sc, sc->first_vty);
3262	}
3263	sc->cur_scp = scp;
3264
3265	/* copy screen to temporary buffer */
3266	sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3267		    (void *)scp->sc->adp->va_window, FALSE);
3268	if (ISTEXTSC(scp))
3269	    sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
3270
3271	/* move cursors to the initial positions */
3272	scp->mouse_pos = scp->mouse_oldpos = 0;
3273	if (col >= scp->xsize)
3274	    col = 0;
3275	if (row >= scp->ysize)
3276	    row = scp->ysize - 1;
3277	scp->xpos = col;
3278	scp->ypos = row;
3279	scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
3280	if (bios_value.cursor_end < scp->font_size)
3281	    sc->cursor_base = scp->font_size - bios_value.cursor_end - 1;
3282	else
3283	    sc->cursor_base = 0;
3284	i = bios_value.cursor_end - bios_value.cursor_start + 1;
3285	sc->cursor_height = imin(i, scp->font_size);
3286	if (!ISGRAPHSC(scp)) {
3287    	    sc_set_cursor_image(scp);
3288    	    draw_cursor_image(scp);
3289	}
3290
3291	/* save font and palette */
3292#ifndef SC_NO_FONT_LOADING
3293	sc->fonts_loaded = 0;
3294	if (ISFONTAVAIL(sc->adp->va_flags)) {
3295#ifdef SC_DFLT_FONT
3296	    bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
3297	    bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
3298	    bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
3299	    sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
3300	    if (scp->font_size < 14) {
3301		copy_font(scp, LOAD, 8, sc->font_8);
3302		sc->fonts_loaded = FONT_8;
3303	    } else if (scp->font_size >= 16) {
3304		copy_font(scp, LOAD, 16, sc->font_16);
3305		sc->fonts_loaded = FONT_16;
3306	    } else {
3307		copy_font(scp, LOAD, 14, sc->font_14);
3308		sc->fonts_loaded = FONT_14;
3309	    }
3310#else /* !SC_DFLT_FONT */
3311	    if (scp->font_size < 14) {
3312		copy_font(scp, SAVE, 8, sc->font_8);
3313		sc->fonts_loaded = FONT_8;
3314	    } else if (scp->font_size >= 16) {
3315		copy_font(scp, SAVE, 16, sc->font_16);
3316		sc->fonts_loaded = FONT_16;
3317	    } else {
3318		copy_font(scp, SAVE, 14, sc->font_14);
3319		sc->fonts_loaded = FONT_14;
3320	    }
3321#endif /* SC_DFLT_FONT */
3322	    /* FONT KLUDGE: always use the font page #0. XXX */
3323	    (*vidsw[sc->adapter]->show_font)(sc->adp, 0);
3324	}
3325#endif /* !SC_NO_FONT_LOADING */
3326
3327#ifndef SC_NO_PALETTE_LOADING
3328	save_palette(sc->adp, sc->palette);
3329#endif
3330
3331#if NSPLASH > 0
3332	if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
3333	    /* we are ready to put up the splash image! */
3334	    splash_init(sc->adp, scsplash_callback, sc);
3335	    sc->flags |= SC_SPLASH_SCRN;
3336	}
3337#endif /* NSPLASH */
3338    }
3339
3340    /* the rest is not necessary, if we have done it once */
3341    if (sc->flags & SC_INIT_DONE)
3342	return;
3343
3344    /* clear structures */
3345    for (i = 1; i < sc->vtys; i++)
3346	sc->console[i] = NULL;
3347
3348    /* initialize mapscrn arrays to a one to one map */
3349    for (i = 0; i < sizeof(sc->scr_map); i++)
3350	sc->scr_map[i] = sc->scr_rmap[i] = i;
3351
3352    sc->flags |= SC_INIT_DONE;
3353}
3354
3355static void
3356scterm(int unit, int flags)
3357{
3358    sc_softc_t *sc;
3359
3360    sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3361    if (sc == NULL)
3362	return;			/* shouldn't happen */
3363
3364#if NSPLASH > 0
3365    /* this console is no longer available for the splash screen */
3366    if (sc->flags & SC_SPLASH_SCRN) {
3367	splash_term(sc->adp);
3368	sc->flags &= ~SC_SPLASH_SCRN;
3369    }
3370#endif /* NSPLASH */
3371
3372#if 0 /* XXX */
3373    /* move the hardware cursor to the upper-left corner */
3374    (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
3375#endif
3376
3377    /* release the keyboard and the video card */
3378    if (sc->keyboard >= 0)
3379	kbd_release(sc->kbd, &sc->keyboard);
3380    if (sc->adapter >= 0)
3381	vid_release(sc->adp, &sc->adapter);
3382
3383    /* clear the structure */
3384    if (!(flags & SC_KERNEL_CONSOLE)) {
3385	free(sc->console, M_DEVBUF);
3386	free(sc->tty, M_DEVBUF);
3387#ifdef DEVFS
3388	free(sc->devfs_token, M_DEVBUF);
3389#endif
3390#ifndef SC_NO_FONT_LOADING
3391	free(sc->font_8, M_DEVBUF);
3392	free(sc->font_14, M_DEVBUF);
3393	free(sc->font_16, M_DEVBUF);
3394#endif
3395	/* XXX vtb, history */
3396    }
3397    bzero(sc, sizeof(*sc));
3398    sc->keyboard = -1;
3399    sc->adapter = -1;
3400}
3401
3402static void
3403scshutdown(int howto, void *arg)
3404{
3405    /* assert(sc_console != NULL) */
3406
3407    sc_touch_scrn_saver();
3408    if (!cold && sc_console
3409	&& sc_console->sc->cur_scp->smode.mode == VT_AUTO
3410	&& sc_console->smode.mode == VT_AUTO)
3411	switch_scr(sc_console->sc, sc_console->index);
3412    shutdown_in_progress = TRUE;
3413}
3414
3415int
3416sc_clean_up(scr_stat *scp)
3417{
3418    int error;
3419
3420    sc_touch_scrn_saver();
3421#if NSPLASH > 0
3422    if ((error = wait_scrn_saver_stop(scp->sc)))
3423	return error;
3424#endif /* NSPLASH */
3425    scp->status &= ~MOUSE_VISIBLE;
3426    sc_remove_cutmarking(scp);
3427    return 0;
3428}
3429
3430void
3431sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
3432{
3433    sc_vtb_t new;
3434    sc_vtb_t old;
3435    int s;
3436
3437    old = scp->vtb;
3438    sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
3439    if (!discard && (old.vtb_flags & VTB_VALID)) {
3440	/* retain the current cursor position and buffer contants */
3441	scp->cursor_oldpos = scp->cursor_pos;
3442	/*
3443	 * This works only if the old buffer has the same size as or larger
3444	 * than the new one. XXX
3445	 */
3446	sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
3447	scp->vtb = new;
3448    } else {
3449        /* clear the screen and move the text cursor to the top-left position */
3450	s = splhigh();
3451	scp->vtb = new;
3452	sc_clear_screen(scp);
3453	splx(s);
3454	sc_vtb_destroy(&old);
3455    }
3456
3457#ifndef SC_NO_SYSMOUSE
3458    /* move the mouse cursor at the center of the screen */
3459    sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
3460#endif
3461}
3462
3463static scr_stat
3464*alloc_scp(sc_softc_t *sc, int vty)
3465{
3466    scr_stat *scp;
3467
3468    /* assert(sc_malloc) */
3469
3470    scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3471    init_scp(sc, vty, scp);
3472
3473    sc_alloc_scr_buffer(scp, TRUE, TRUE);
3474
3475#ifndef SC_NO_SYSMOUSE
3476    if (ISMOUSEAVAIL(sc->adp->va_flags))
3477	sc_alloc_cut_buffer(scp, TRUE);
3478#endif
3479
3480#ifndef SC_NO_HISTORY
3481    sc_alloc_history_buffer(scp, 0, TRUE);
3482#endif
3483
3484    sc_clear_screen(scp);
3485    return scp;
3486}
3487
3488static void
3489init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
3490{
3491    video_info_t info;
3492
3493    scp->index = vty;
3494    scp->sc = sc;
3495    scp->status = 0;
3496    scp->mode = sc->initial_mode;
3497    (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
3498    if (info.vi_flags & V_INFO_GRAPHICS) {
3499	scp->status |= GRAPHICS_MODE;
3500	scp->xpixel = info.vi_width;
3501	scp->ypixel = info.vi_height;
3502	scp->xsize = info.vi_width/8;
3503	scp->ysize = info.vi_height/info.vi_cheight;
3504	scp->font_size = FONT_NONE;
3505	scp->font = NULL;
3506    } else {
3507	scp->xsize = info.vi_width;
3508	scp->ysize = info.vi_height;
3509	scp->xpixel = scp->xsize*8;
3510	scp->ypixel = scp->ysize*info.vi_cheight;
3511	if (info.vi_cheight < 14) {
3512	    scp->font_size = 8;
3513#ifndef SC_NO_FONT_LOADING
3514	    scp->font = sc->font_8;
3515#else
3516	    scp->font = NULL;
3517#endif
3518	} else if (info.vi_cheight >= 16) {
3519	    scp->font_size = 16;
3520#ifndef SC_NO_FONT_LOADING
3521	    scp->font = sc->font_16;
3522#else
3523	    scp->font = NULL;
3524#endif
3525	} else {
3526	    scp->font_size = 14;
3527#ifndef SC_NO_FONT_LOADING
3528	    scp->font = sc->font_14;
3529#else
3530	    scp->font = NULL;
3531#endif
3532	}
3533    }
3534    sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
3535    sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
3536    scp->xoff = scp->yoff = 0;
3537    scp->xpos = scp->ypos = 0;
3538    scp->saved_xpos = scp->saved_ypos = -1;
3539    scp->start = scp->xsize * scp->ysize - 1;
3540    scp->end = 0;
3541    scp->term.esc = 0;
3542    scp->term.attr_mask = NORMAL_ATTR;
3543    scp->term.cur_attr =
3544	scp->term.cur_color = scp->term.std_color =
3545	current_default->std_color;
3546    scp->term.rev_color = current_default->rev_color;
3547    scp->border = BG_BLACK;
3548    scp->cursor_base = sc->cursor_base;
3549    scp->cursor_height = imin(sc->cursor_height, scp->font_size);
3550    scp->mouse_xpos = scp->xoff*8 + scp->xsize*8/2;
3551    scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size/2;
3552    scp->mouse_cut_start = scp->xsize*scp->ysize;
3553    scp->mouse_cut_end = -1;
3554    scp->mouse_signal = 0;
3555    scp->mouse_pid = 0;
3556    scp->mouse_proc = NULL;
3557    scp->kbd_mode = K_XLATE;
3558    scp->bell_pitch = bios_value.bell_pitch;
3559    scp->bell_duration = BELL_DURATION;
3560    scp->status |= (bios_value.shift_state & NLKED);
3561    scp->status |= CURSOR_ENABLED;
3562    scp->pid = 0;
3563    scp->proc = NULL;
3564    scp->smode.mode = VT_AUTO;
3565    scp->history = NULL;
3566    scp->history_pos = 0;
3567    scp->history_size = 0;
3568
3569    /* what if the following call fails... XXX */
3570    scp->rndr = sc_render_match(scp, scp->sc->adp,
3571				scp->status & (GRAPHICS_MODE | PIXEL_MODE));
3572}
3573
3574/*
3575 * scgetc(flags) - get character from keyboard.
3576 * If flags & SCGETC_CN, then avoid harmful side effects.
3577 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3578 * return NOKEY if there is nothing there.
3579 */
3580static u_int
3581scgetc(sc_softc_t *sc, u_int flags)
3582{
3583    scr_stat *scp;
3584    u_int c;
3585    int this_scr;
3586    int f;
3587    int i;
3588
3589    if (sc->kbd == NULL)
3590	return NOKEY;
3591
3592next_code:
3593#if 1
3594    /* I don't like this, but... XXX */
3595    if (flags & SCGETC_CN)
3596	sccnupdate(sc->cur_scp);
3597#endif
3598    scp = sc->cur_scp;
3599    /* first see if there is something in the keyboard port */
3600    for (;;) {
3601	c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
3602	if (c == ERRKEY) {
3603	    if (!(flags & SCGETC_CN))
3604		do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3605	} else if (c == NOKEY)
3606	    return c;
3607	else
3608	    break;
3609    }
3610
3611    /* make screensaver happy */
3612    if (!(c & RELKEY))
3613	sc_touch_scrn_saver();
3614
3615#ifdef __i386__
3616    if (!(flags & SCGETC_CN))
3617	/* do the /dev/random device a favour */
3618	add_keyboard_randomness(c);
3619#endif
3620
3621    if (scp->kbd_mode != K_XLATE)
3622	return KEYCHAR(c);
3623
3624    /* if scroll-lock pressed allow history browsing */
3625    if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
3626
3627	scp->status &= ~CURSOR_ENABLED;
3628	remove_cursor_image(scp);
3629
3630#ifndef SC_NO_HISTORY
3631	if (!(scp->status & BUFFER_SAVED)) {
3632	    scp->status |= BUFFER_SAVED;
3633	    sc_hist_save(scp);
3634	}
3635	switch (c) {
3636	/* FIXME: key codes */
3637	case SPCLKEY | FKEY | F(49):  /* home key */
3638	    sc_remove_cutmarking(scp);
3639	    sc_hist_home(scp);
3640	    goto next_code;
3641
3642	case SPCLKEY | FKEY | F(57):  /* end key */
3643	    sc_remove_cutmarking(scp);
3644	    sc_hist_end(scp);
3645	    goto next_code;
3646
3647	case SPCLKEY | FKEY | F(50):  /* up arrow key */
3648	    sc_remove_cutmarking(scp);
3649	    if (sc_hist_up_line(scp))
3650		if (!(flags & SCGETC_CN))
3651		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3652	    goto next_code;
3653
3654	case SPCLKEY | FKEY | F(58):  /* down arrow key */
3655	    sc_remove_cutmarking(scp);
3656	    if (sc_hist_down_line(scp))
3657		if (!(flags & SCGETC_CN))
3658		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3659	    goto next_code;
3660
3661	case SPCLKEY | FKEY | F(51):  /* page up key */
3662	    sc_remove_cutmarking(scp);
3663	    for (i=0; i<scp->ysize; i++)
3664	    if (sc_hist_up_line(scp)) {
3665		if (!(flags & SCGETC_CN))
3666		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3667		break;
3668	    }
3669	    goto next_code;
3670
3671	case SPCLKEY | FKEY | F(59):  /* page down key */
3672	    sc_remove_cutmarking(scp);
3673	    for (i=0; i<scp->ysize; i++)
3674	    if (sc_hist_down_line(scp)) {
3675		if (!(flags & SCGETC_CN))
3676		    do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3677		break;
3678	    }
3679	    goto next_code;
3680	}
3681#endif /* SC_NO_HISTORY */
3682    }
3683
3684    /*
3685     * Process and consume special keys here.  Return a plain char code
3686     * or a char code with the META flag or a function key code.
3687     */
3688    if (c & RELKEY) {
3689	/* key released */
3690	/* goto next_code */
3691    } else {
3692	/* key pressed */
3693	if (c & SPCLKEY) {
3694	    c &= ~SPCLKEY;
3695	    switch (KEYCHAR(c)) {
3696	    /* LOCKING KEYS */
3697	    case NLK: case CLK: case ALK:
3698		break;
3699	    case SLK:
3700		kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3701		if (f & SLKED) {
3702		    scp->status |= SLKED;
3703		} else {
3704		    if (scp->status & SLKED) {
3705			scp->status &= ~SLKED;
3706#ifndef SC_NO_HISTORY
3707			if (scp->status & BUFFER_SAVED) {
3708			    if (!sc_hist_restore(scp))
3709				sc_remove_cutmarking(scp);
3710			    scp->status &= ~BUFFER_SAVED;
3711			    scp->status |= CURSOR_ENABLED;
3712			    draw_cursor_image(scp);
3713			}
3714#endif
3715			scstart(VIRTUAL_TTY(sc, scp->index));
3716		    }
3717		}
3718		break;
3719
3720	    /* NON-LOCKING KEYS */
3721	    case NOP:
3722	    case LSH:  case RSH:  case LCTR: case RCTR:
3723	    case LALT: case RALT: case ASH:  case META:
3724		break;
3725
3726	    case BTAB:
3727		if (!(sc->flags & SC_SCRN_BLANKED))
3728		    return c;
3729		break;
3730
3731	    case SPSC:
3732#if NSPLASH > 0
3733		/* force activatation/deactivation of the screen saver */
3734		if (!(sc->flags & SC_SCRN_BLANKED)) {
3735		    run_scrn_saver = TRUE;
3736		    sc->scrn_time_stamp -= scrn_blank_time;
3737		}
3738		if (cold) {
3739		    /*
3740		     * While devices are being probed, the screen saver need
3741		     * to be invoked explictly. XXX
3742		     */
3743		    if (sc->flags & SC_SCRN_BLANKED) {
3744			scsplash_stick(FALSE);
3745			stop_scrn_saver(sc, current_saver);
3746		    } else {
3747			if (!ISGRAPHSC(scp)) {
3748			    scsplash_stick(TRUE);
3749			    (*current_saver)(sc, TRUE);
3750			}
3751		    }
3752		}
3753#endif /* NSPLASH */
3754		break;
3755
3756	    case RBT:
3757#ifndef SC_DISABLE_REBOOT
3758		shutdown_nice();
3759#endif
3760		break;
3761
3762#if NAPM > 0
3763	    case SUSP:
3764		apm_suspend(PMST_SUSPEND);
3765		break;
3766	    case STBY:
3767		apm_suspend(PMST_STANDBY);
3768		break;
3769#else
3770	    case SUSP:
3771	    case STBY:
3772		break;
3773#endif
3774
3775	    case DBG:
3776#ifndef SC_DISABLE_DDBKEY
3777#ifdef DDB
3778		if (debugger)
3779		    break;
3780		/* try to switch to the kernel console screen */
3781		if (sc_console) {
3782		    /*
3783		     * TRY to make sure the screen saver is stopped,
3784		     * and the screen is updated before switching to
3785		     * the vty0.
3786		     */
3787		    scrn_timer(NULL);
3788		    if (!cold
3789			&& sc_console->sc->cur_scp->smode.mode == VT_AUTO
3790			&& sc_console->smode.mode == VT_AUTO)
3791			switch_scr(sc_console->sc, sc_console->index);
3792		}
3793		Debugger("manual escape to debugger");
3794#else
3795		printf("No debugger in kernel\n");
3796#endif
3797#else /* SC_DISABLE_DDBKEY */
3798		/* do nothing */
3799#endif /* SC_DISABLE_DDBKEY */
3800		break;
3801
3802	    case NEXT:
3803		this_scr = scp->index;
3804		for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3805			sc->first_vty + i != this_scr;
3806			i = (i + 1)%sc->vtys) {
3807		    struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3808		    if (tp->t_state & TS_ISOPEN) {
3809			switch_scr(scp->sc, sc->first_vty + i);
3810			break;
3811		    }
3812		}
3813		break;
3814
3815	    case PREV:
3816		this_scr = scp->index;
3817		for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3818			sc->first_vty + i != this_scr;
3819			i = (i + sc->vtys - 1)%sc->vtys) {
3820		    struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3821		    if (tp->t_state & TS_ISOPEN) {
3822			switch_scr(scp->sc, sc->first_vty + i);
3823			break;
3824		    }
3825		}
3826		break;
3827
3828	    default:
3829		if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3830		    switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3831		    break;
3832		}
3833		/* assert(c & FKEY) */
3834		if (!(sc->flags & SC_SCRN_BLANKED))
3835		    return c;
3836		break;
3837	    }
3838	    /* goto next_code */
3839	} else {
3840	    /* regular keys (maybe MKEY is set) */
3841	    if (!(sc->flags & SC_SCRN_BLANKED))
3842		return c;
3843	}
3844    }
3845
3846    goto next_code;
3847}
3848
3849int
3850scmmap(dev_t dev, vm_offset_t offset, int nprot)
3851{
3852    struct tty *tp;
3853    struct scr_stat *scp;
3854
3855    tp = scdevtotty(dev);
3856    if (!tp)
3857	return ENXIO;
3858    scp = sc_get_scr_stat(tp->t_dev);
3859    return (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, offset, nprot);
3860}
3861
3862/*
3863 * Calculate hardware attributes word using logical attributes mask and
3864 * hardware colors
3865 */
3866
3867static int
3868mask2attr(struct term_stat *term)
3869{
3870    int attr, mask = term->attr_mask;
3871
3872    if (mask & REVERSE_ATTR) {
3873	attr = ((mask & FOREGROUND_CHANGED) ?
3874		((term->cur_color & 0xF000) >> 4) :
3875		(term->rev_color & 0x0F00)) |
3876	       ((mask & BACKGROUND_CHANGED) ?
3877		((term->cur_color & 0x0F00) << 4) :
3878		(term->rev_color & 0xF000));
3879    } else
3880	attr = term->cur_color;
3881
3882    /* XXX: underline mapping for Hercules adapter can be better */
3883    if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3884	attr ^= 0x0800;
3885    if (mask & BLINK_ATTR)
3886	attr ^= 0x8000;
3887
3888    return attr;
3889}
3890
3891static int
3892save_kbd_state(scr_stat *scp)
3893{
3894    int state;
3895    int error;
3896
3897    error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3898    if (error == ENOIOCTL)
3899	error = ENODEV;
3900    if (error == 0) {
3901	scp->status &= ~LOCK_MASK;
3902	scp->status |= state;
3903    }
3904    return error;
3905}
3906
3907static int
3908update_kbd_state(scr_stat *scp, int new_bits, int mask)
3909{
3910    int state;
3911    int error;
3912
3913    if (mask != LOCK_MASK) {
3914	error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3915	if (error == ENOIOCTL)
3916	    error = ENODEV;
3917	if (error)
3918	    return error;
3919	state &= ~mask;
3920	state |= new_bits & mask;
3921    } else {
3922	state = new_bits & LOCK_MASK;
3923    }
3924    error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3925    if (error == ENOIOCTL)
3926	error = ENODEV;
3927    return error;
3928}
3929
3930static int
3931update_kbd_leds(scr_stat *scp, int which)
3932{
3933    int error;
3934
3935    which &= LOCK_MASK;
3936    error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3937    if (error == ENOIOCTL)
3938	error = ENODEV;
3939    return error;
3940}
3941
3942int
3943set_mode(scr_stat *scp)
3944{
3945    video_info_t info;
3946
3947    /* reject unsupported mode */
3948    if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
3949	return 1;
3950
3951    /* if this vty is not currently showing, do nothing */
3952    if (scp != scp->sc->cur_scp)
3953	return 0;
3954
3955    /* setup video hardware for the given mode */
3956    (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3957    sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3958		(void *)scp->sc->adp->va_window, FALSE);
3959
3960#ifndef SC_NO_FONT_LOADING
3961    /* load appropriate font */
3962    if (!(scp->status & GRAPHICS_MODE)) {
3963	if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3964	    if (scp->font_size < 14) {
3965		if (scp->sc->fonts_loaded & FONT_8)
3966		    copy_font(scp, LOAD, 8, scp->sc->font_8);
3967	    } else if (scp->font_size >= 16) {
3968		if (scp->sc->fonts_loaded & FONT_16)
3969		    copy_font(scp, LOAD, 16, scp->sc->font_16);
3970	    } else {
3971		if (scp->sc->fonts_loaded & FONT_14)
3972		    copy_font(scp, LOAD, 14, scp->sc->font_14);
3973	    }
3974	    /*
3975	     * FONT KLUDGE:
3976	     * This is an interim kludge to display correct font.
3977	     * Always use the font page #0 on the video plane 2.
3978	     * Somehow we cannot show the font in other font pages on
3979	     * some video cards... XXX
3980	     */
3981	    (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, 0);
3982	}
3983	mark_all(scp);
3984    }
3985#endif /* !SC_NO_FONT_LOADING */
3986
3987    set_border(scp, scp->border);
3988    sc_set_cursor_image(scp);
3989
3990    return 0;
3991}
3992
3993void
3994set_border(scr_stat *scp, int color)
3995{
3996    ++scp->sc->videoio_in_progress;
3997    (*scp->rndr->draw_border)(scp, color);
3998    --scp->sc->videoio_in_progress;
3999}
4000
4001#ifndef SC_NO_FONT_LOADING
4002void
4003copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
4004{
4005    /*
4006     * FONT KLUDGE:
4007     * This is an interim kludge to display correct font.
4008     * Always use the font page #0 on the video plane 2.
4009     * Somehow we cannot show the font in other font pages on
4010     * some video cards... XXX
4011     */
4012    scp->sc->font_loading_in_progress = TRUE;
4013    if (operation == LOAD) {
4014	(*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, font_size,
4015					      buf, 0, 256);
4016    } else if (operation == SAVE) {
4017	(*vidsw[scp->sc->adapter]->save_font)(scp->sc->adp, 0, font_size,
4018					      buf, 0, 256);
4019    }
4020    scp->sc->font_loading_in_progress = FALSE;
4021}
4022#endif /* !SC_NO_FONT_LOADING */
4023
4024#ifndef SC_NO_SYSMOUSE
4025struct tty
4026*sc_get_mouse_tty(void)
4027{
4028    return MOUSE_TTY;
4029}
4030#endif /* !SC_NO_SYSMOUSE */
4031
4032#ifndef SC_NO_CUTPASTE
4033void
4034sc_paste(scr_stat *scp, u_char *p, int count)
4035{
4036    struct tty *tp;
4037    u_char *rmap;
4038
4039    if (scp->status & MOUSE_VISIBLE) {
4040	tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
4041	rmap = scp->sc->scr_rmap;
4042	for (; count > 0; --count)
4043	    (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
4044    }
4045}
4046#endif /* SC_NO_CUTPASTE */
4047
4048static void
4049do_bell(scr_stat *scp, int pitch, int duration)
4050{
4051    if (cold || shutdown_in_progress)
4052	return;
4053
4054    if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL))
4055	return;
4056
4057    if (scp->sc->flags & SC_VISUAL_BELL) {
4058	if (scp->sc->blink_in_progress)
4059	    return;
4060	scp->sc->blink_in_progress = 3;
4061	if (scp != scp->sc->cur_scp)
4062	    scp->sc->blink_in_progress += 2;
4063	blink_screen(scp->sc->cur_scp);
4064    } else {
4065	if (scp != scp->sc->cur_scp)
4066	    pitch *= 2;
4067	sysbeep(pitch, duration);
4068    }
4069}
4070
4071static void
4072blink_screen(void *arg)
4073{
4074    scr_stat *scp = arg;
4075
4076    if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
4077	scp->sc->blink_in_progress = 0;
4078    	mark_all(scp);
4079	scstart(VIRTUAL_TTY(scp->sc, scp->index));
4080	if (scp->sc->delayed_next_scr)
4081	    switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
4082    }
4083    else {
4084	(*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
4085			   scp->sc->blink_in_progress & 1);
4086	scp->sc->blink_in_progress--;
4087	timeout(blink_screen, scp, hz / 10);
4088    }
4089}
4090
4091#endif /* NSC */
4092