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