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