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