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