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