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