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