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