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