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