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