xref: /freebsd/sys/dev/syscons/syscons.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
1 /*-
2  * Copyright (c) 1992-1995 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  *    in this position and unchanged.
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 withough 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.115 1995/04/28 09:10:56 sos Exp $
29  */
30 
31 #include "sc.h"
32 #include "apm.h"
33 #if NSC > 0
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/ioctl.h>
38 #include <sys/proc.h>
39 #include <sys/user.h>
40 #include <sys/tty.h>
41 #include <sys/uio.h>
42 #include <sys/callout.h>
43 #include <sys/kernel.h>
44 #include <sys/syslog.h>
45 #include <sys/errno.h>
46 #include <sys/malloc.h>
47 #include <sys/devconf.h>
48 
49 #include <machine/clock.h>
50 #include <machine/console.h>
51 #include <machine/psl.h>
52 #include <machine/frame.h>
53 #include <machine/pc/display.h>
54 #include <machine/apm_bios.h>
55 
56 #include <i386/isa/isa.h>
57 #include <i386/isa/isa_device.h>
58 #include <i386/isa/timerreg.h>
59 #include <i386/isa/kbdtables.h>
60 #include <i386/i386/cons.h>
61 #include <i386/isa/syscons.h>
62 
63 #if !defined(MAXCONS)
64 #define MAXCONS 16
65 #endif
66 
67 /* this may break on older VGA's but is usefull on real 32 bit systems */
68 #define bcopyw  bcopy
69 
70 static default_attr user_default = {
71     (FG_LIGHTGREY | BG_BLACK) << 8,
72     (FG_BLACK | BG_LIGHTGREY) << 8
73 };
74 
75 static default_attr kernel_default = {
76     (FG_WHITE | BG_BLACK) << 8,
77     (FG_BLACK | BG_LIGHTGREY) << 8
78 };
79 
80 static  scr_stat    	main_console;
81 static  scr_stat    	*console[MAXCONS];
82 	scr_stat    	*cur_console;
83 static  scr_stat    	*new_scp, *old_scp;
84 static  term_stat   	kernel_console;
85 static  default_attr    *current_default;
86 static  char        	init_done = FALSE;
87 static  int     	configuration = 0;
88 static  char        	switch_in_progress = FALSE;
89 static  char        	blink_in_progress = FALSE;
90 static  char        	write_in_progress = FALSE;
91 	u_int       	crtc_addr = MONO_BASE;
92 static  char        	crtc_vga = FALSE;
93 static  u_char      	shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
94 static  u_char      	nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
95 static  char        	*font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
96 static  int     	fonts_loaded = 0;
97 	char        	palette[3*256];
98 static  const u_int     n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
99 static  int     	delayed_next_scr = FALSE;
100 static  long        	scrn_blank_time = 0;    /* screen saver timeout value */
101 	int     	scrn_blanked = FALSE;   /* screen saver active flag */
102 static  int     	scrn_saver = 0;    	/* screen saver routine */
103 static  long       	scrn_time_stamp;
104 	u_char      	scr_map[256];
105 static  char        	*video_mode_ptr = NULL;
106 #if ASYNCH
107 static  u_char      	kbd_reply = 0;
108 #endif
109 
110 static  u_short mouse_and_mask[16] = {
111 	0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
112 	0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
113 };
114 static  u_short mouse_or_mask[16] = {
115 	0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
116 	0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
117 };
118 
119 void    none_saver(int blank) { }
120 void    (*current_saver)() = none_saver;
121 
122 /* OS specific stuff */
123 #ifdef not_yet_done
124 #define VIRTUAL_TTY(x)  (sccons[x] = ttymalloc(sccons[x]))
125 struct  CONSOLE_TTY 	(sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
126 struct  tty         	*sccons[MAXCONS+1];
127 #else
128 #define VIRTUAL_TTY(x)  &sccons[x]
129 #define CONSOLE_TTY 	&sccons[MAXCONS]
130 struct  tty         	sccons[MAXCONS+1];
131 int			nsccons = MAXCONS+1;
132 #endif
133 #define MONO_BUF    	pa_to_va(0xB0000)
134 #define CGA_BUF     	pa_to_va(0xB8000)
135 u_short         	*Crtat = (u_short *)MONO_BUF;
136 
137 #define WRAPHIST(scp, pointer, offset)\
138     ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
139     + (offset)) % (scp->history_size)))
140 
141 struct  isa_driver scdriver = {
142     scprobe, scattach, "sc", 1
143 };
144 
145 int
146 scprobe(struct isa_device *dev)
147 {
148     int i, retries = 5;
149     unsigned char val;
150 
151     /* Enable interrupts and keyboard controller */
152     kbd_wait();
153     outb(KB_STAT, KB_WRITE);
154     kbd_wait();
155     outb(KB_DATA, KB_MODE);
156 
157     /* flush any noise in the buffer */
158     while (inb(KB_STAT) & KB_BUF_FULL) {
159 	DELAY(10);
160 	(void) inb(KB_DATA);
161     }
162 
163     /* Reset keyboard hardware */
164     while (retries--) {
165 	kbd_wait();
166 	outb(KB_DATA, KB_RESET);
167 	for (i=0; i<100000; i++) {
168 	    DELAY(10);
169 	    val = inb(KB_DATA);
170 	    if (val == KB_ACK || val == KB_ECHO)
171 		goto gotres;
172 	    if (val == KB_RESEND)
173 		break;
174 	}
175     }
176 gotres:
177     if (!retries)
178 	printf("scprobe: keyboard won't accept RESET command\n");
179     else {
180 gotack:
181 	DELAY(10);
182 	while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
183 	DELAY(10);
184 	val = inb(KB_DATA);
185 	if (val == KB_ACK)
186 	    goto gotack;
187 	if (val != KB_RESET_DONE)
188 	    printf("scprobe: keyboard RESET failed %02x\n", val);
189     }
190 #ifdef XT_KEYBOARD
191     kbd_wait();
192     outb(KB_DATA, 0xF0);
193     kbd_wait();
194     outb(KB_DATA, 1)
195     kbd_wait();
196 #endif /* XT_KEYBOARD */
197     return (IO_KBDSIZE);
198 }
199 
200 static struct kern_devconf kdc_sc[NSC] = {
201     0, 0, 0,        		/* filled in by dev_attach */
202     "sc", 0, { MDDT_ISA, 0, "tty" },
203     isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
204     &kdc_isa0,      		/* parent */
205     0,          		/* parentdata */
206     DC_BUSY,        		/* the console is almost always busy */
207     "Graphics console",
208     DC_CLS_DISPLAY		/* class */
209 };
210 
211 static inline void
212 sc_registerdev(struct isa_device *id)
213 {
214     if(id->id_unit)
215 	kdc_sc[id->id_unit] = kdc_sc[0];
216     kdc_sc[id->id_unit].kdc_unit = id->id_unit;
217     kdc_sc[id->id_unit].kdc_isa = id;
218     dev_attach(&kdc_sc[id->id_unit]);
219 }
220 
221 #if NAPM > 0
222 static int
223 scresume(void *dummy)
224 {
225 	shfts = 0;
226 	ctls = 0;
227 	alts = 0;
228 	agrs = 0;
229 	metas = 0;
230 	return 0;
231 }
232 #endif
233 
234 int
235 scattach(struct isa_device *dev)
236 {
237     scr_stat *scp;
238 
239     scinit();
240     configuration = dev->id_flags;
241 
242     scp = console[0];
243 
244     if (crtc_vga) {
245 	font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
246 	font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
247 	font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
248 	copy_font(SAVE, FONT_16, font_16);
249 	fonts_loaded = FONT_16;
250 	scp->font = FONT_16;
251 	save_palette();
252     }
253 
254     scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
255 				     M_DEVBUF, M_NOWAIT);
256     /* copy screen to buffer */
257     bcopyw(Crtat, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
258     scp->cursor_pos = scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
259     scp->mouse_pos = scp->scr_buf;
260 
261     /* initialize history buffer & pointers */
262     scp->history_head = scp->history_pos = scp->history =
263 	(u_short *)malloc(scp->history_size*sizeof(u_short),
264 			  M_DEVBUF, M_NOWAIT);
265     bzero(scp->history_head, scp->history_size*sizeof(u_short));
266 
267     /* initialize cursor stuff */
268     draw_cursor(scp, TRUE);
269     if (crtc_vga && (configuration & CHAR_CURSOR))
270 	set_destructive_cursor(scp, TRUE);
271 
272     /* get screen update going */
273     scrn_timer();
274 
275     update_leds(scp->status);
276     sc_registerdev(dev);
277 
278     printf("sc%d: ", dev->id_unit);
279     if (crtc_vga)
280 	if (crtc_addr == MONO_BASE)
281 	    printf("VGA mono");
282 	else
283 	    printf("VGA color");
284     else
285 	if (crtc_addr == MONO_BASE)
286 	    printf("MDA/hercules");
287 	else
288 	    printf("CGA/EGA");
289     printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, configuration);
290 
291 #if NAPM > 0
292     scp->r_hook.ah_fun = scresume;
293     scp->r_hook.ah_arg = NULL;
294     scp->r_hook.ah_name = "system keyboard";
295     scp->r_hook.ah_order = APM_MID_ORDER;
296     apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
297 #endif
298     return 0;
299 }
300 
301 struct tty
302 *scdevtotty(dev_t dev)
303 {
304     int unit = minor(dev);
305 
306     if (unit > MAXCONS || unit < 0)
307 	return(NULL);
308     if (unit == MAXCONS)
309 	return CONSOLE_TTY;
310     return VIRTUAL_TTY(unit);
311 }
312 
313 static scr_stat
314 *get_scr_stat(dev_t dev)
315 {
316     int unit = minor(dev);
317 
318     if (unit > MAXCONS || unit < 0)
319 	return(NULL);
320     if (unit == MAXCONS)
321 	return console[0];
322     return console[unit];
323 }
324 
325 static int
326 get_scr_num()
327 {
328     int i = 0;
329 
330     while ((i < MAXCONS) && (cur_console != console[i]))
331 	i++;
332     return i < MAXCONS ? i : 0;
333 }
334 
335 int
336 scopen(dev_t dev, int flag, int mode, struct proc *p)
337 {
338     struct tty *tp = scdevtotty(dev);
339 
340     if (!tp)
341 	return(ENXIO);
342 
343     tp->t_oproc = scstart;
344     tp->t_param = scparam;
345     tp->t_dev = dev;
346     if (!(tp->t_state & TS_ISOPEN)) {
347 	ttychars(tp);
348 	tp->t_iflag = TTYDEF_IFLAG;
349 	tp->t_oflag = TTYDEF_OFLAG;
350 	tp->t_cflag = TTYDEF_CFLAG;
351 	tp->t_lflag = TTYDEF_LFLAG;
352 	tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
353 	scparam(tp, &tp->t_termios);
354 	ttsetwater(tp);
355     }
356     else
357 	if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
358 	    return(EBUSY);
359     tp->t_state |= TS_CARR_ON;
360     tp->t_cflag |= CLOCAL;
361     if (!console[minor(dev)])
362 	console[minor(dev)] = alloc_scp();
363     return((*linesw[tp->t_line].l_open)(dev, tp));
364 }
365 
366 int
367 scclose(dev_t dev, int flag, int mode, struct proc *p)
368 {
369     struct tty *tp = scdevtotty(dev);
370     struct scr_stat *scp;
371 
372     if (!tp)
373 	return(ENXIO);
374     if (minor(dev) < MAXCONS) {
375 	scp = get_scr_stat(tp->t_dev);
376 	if (scp->status & SWITCH_WAIT_ACQ)
377 	    wakeup((caddr_t)&scp->smode);
378 #if not_yet_done
379 	if (scp == &main_console) {
380 	    scp->pid = 0;
381 	    scp->proc = NULL;
382 	    scp->smode.mode = VT_AUTO;
383 	}
384 	else {
385 	    free(scp->scr_buf, M_DEVBUF);
386 	    free(scp->history, M_DEVBUF);
387 	    free(scp, M_DEVBUF);
388 	    console[minor(dev)] = NULL;
389 	}
390 #else
391 	scp->pid = 0;
392 	scp->proc = NULL;
393 	scp->smode.mode = VT_AUTO;
394 #endif
395     }
396     (*linesw[tp->t_line].l_close)(tp, flag);
397     ttyclose(tp);
398     return(0);
399 }
400 
401 int
402 scread(dev_t dev, struct uio *uio, int flag)
403 {
404     struct tty *tp = scdevtotty(dev);
405 
406     if (!tp)
407 	return(ENXIO);
408     return((*linesw[tp->t_line].l_read)(tp, uio, flag));
409 }
410 
411 int
412 scwrite(dev_t dev, struct uio *uio, int flag)
413 {
414     struct tty *tp = scdevtotty(dev);
415 
416     if (!tp)
417 	return(ENXIO);
418     return((*linesw[tp->t_line].l_write)(tp, uio, flag));
419 }
420 
421 void
422 scintr(int unit)
423 {
424     static struct tty *cur_tty;
425     int c, len;
426     u_char *cp;
427 
428     /* make screensaver happy */
429     scrn_time_stamp = time.tv_sec;
430     if (scrn_blanked) {
431 	(*current_saver)(FALSE);
432 	cur_console->start = 0;
433 	cur_console->end = cur_console->xsize * cur_console->ysize;
434     }
435 
436     c = scgetc(1);
437 
438     cur_tty = VIRTUAL_TTY(get_scr_num());
439     if (!(cur_tty->t_state & TS_ISOPEN))
440 	if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
441 	    return;
442 
443     switch (c & 0xff00) {
444     case 0x0000: /* normal key */
445 	(*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
446 	break;
447     case NOKEY: /* nothing there */
448 	break;
449     case FKEY:  /* function key, return string */
450 	if (cp = get_fstr((u_int)c, (u_int *)&len)) {
451 	    while (len-- >  0)
452 		(*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
453 	}
454 	break;
455     case MKEY:  /* meta is active, prepend ESC */
456 	(*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
457 	(*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
458 	break;
459     case BKEY:  /* backtab fixed sequence (esc [ Z) */
460 	(*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
461 	(*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
462 	(*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
463 	break;
464     }
465 }
466 
467 int
468 scparam(struct tty *tp, struct termios *t)
469 {
470     tp->t_ispeed = t->c_ispeed;
471     tp->t_ospeed = t->c_ospeed;
472     tp->t_cflag = t->c_cflag;
473     return 0;
474 }
475 
476 int
477 scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
478 {
479     int i, error;
480     struct tty *tp;
481     struct trapframe *fp;
482     scr_stat *scp;
483 
484     tp = scdevtotty(dev);
485     if (!tp)
486 	return ENXIO;
487     scp = get_scr_stat(tp->t_dev);
488 
489     switch (cmd) {  		/* process console hardware related ioctl's */
490 
491     case GIO_ATTR:      	/* get current attributes */
492 	*(int*)data = scp->term.cur_attr;
493 	return 0;
494 
495     case GIO_COLOR:     	/* is this a color console ? */
496 	if (crtc_addr == COLOR_BASE)
497 	    *(int*)data = 1;
498 	else
499 	    *(int*)data = 0;
500 	return 0;
501 
502     case CONS_CURRENT:  	/* get current adapter type */
503 	if (crtc_vga)
504 	    *(int*)data = KD_VGA;
505 	else
506 	    if (crtc_addr == MONO_BASE)
507 		*(int*)data = KD_MONO;
508 	    else
509 		*(int*)data = KD_CGA;
510 	return 0;
511 
512     case CONS_GET:      	/* get current video mode */
513 	*(int*)data = scp->mode;
514 	return 0;
515 
516     case CONS_BLANKTIME:    	/* set screen saver timeout (0 = no saver) */
517 	scrn_blank_time = *(int*)data;
518 	return 0;
519 
520     case CONS_CURSORTYPE:   	/* set cursor type blink/noblink */
521 	if ((*(int*)data) & 0x01)
522 	    configuration |= BLINK_CURSOR;
523 	else
524 	    configuration &= ~BLINK_CURSOR;
525 	if ((*(int*)data) & 0x02) {
526 	    configuration |= CHAR_CURSOR;
527 	    set_destructive_cursor(scp, TRUE);
528 	} else
529 	    configuration &= ~CHAR_CURSOR;
530 	return 0;
531 
532     case CONS_BELLTYPE: 	/* set bell type sound/visual */
533 	if (*data)
534 	    configuration |= VISUAL_BELL;
535 	else
536 	    configuration &= ~VISUAL_BELL;
537 	return 0;
538 
539     case CONS_HISTORY:  	/* set history size */
540 	if (*data) {
541 	    free(scp->history, M_DEVBUF);
542 	    scp->history_size = *(int*)data;
543 	    if (scp->history_size < scp->ysize)
544 		scp->history = NULL;
545 	    else {
546 		scp->history_size *= scp->xsize;
547 		scp->history_head = scp->history_pos = scp->history =
548 		    (u_short *)malloc(scp->history_size*sizeof(u_short),
549 				      M_DEVBUF, M_NOWAIT);
550 		bzero(scp->history_head, scp->history_size*sizeof(u_short));
551 	    }
552 	    return 0;
553 	}
554 	else
555 	    return EINVAL;
556 
557     case CONS_MOUSECTL:		/* control mouse arrow */
558     {
559 	mouse_info_t *mouse = (mouse_info_t*)data;
560 	int fontsize;
561 
562 	switch (scp->font) {
563 	default:
564 	case FONT_8:
565 	    fontsize = 8; break;
566 	case FONT_14:
567 	    fontsize = 14; break;
568 	case FONT_16:
569 	    fontsize = 16; break;
570 	}
571 	switch (mouse->operation) {
572 	case MOUSE_SHOW:
573 	    if (!(scp->status & MOUSE_ENABLED)) {
574 		scp->mouse_oldpos = Crtat + (scp->mouse_pos - scp->scr_buf);
575 		scp->status |= (UPDATE_MOUSE | MOUSE_ENABLED);
576 	    }
577 	    else
578 		return EINVAL;
579 	    break;
580 
581 	case MOUSE_HIDE:
582 	    if (scp->status & MOUSE_ENABLED) {
583 		scp->status &= ~MOUSE_ENABLED;
584 		scp->status |= UPDATE_MOUSE;
585 	    }
586 	    else
587 		return EINVAL;
588 	    break;
589 
590 	case MOUSE_MOVEABS:
591 	    scp->mouse_xpos = mouse->x;
592 	    scp->mouse_ypos = mouse->y;
593 	    goto set_mouse_pos;
594 
595 	case MOUSE_MOVEREL:
596 	    scp->mouse_xpos += mouse->x;
597 	    scp->mouse_ypos += mouse->y;
598 set_mouse_pos:
599 	    if (scp->mouse_xpos < 0)
600 		scp->mouse_xpos = 0;
601 	    if (scp->mouse_ypos < 0)
602 		scp->mouse_ypos = 0;
603 	    if (scp->mouse_xpos >= scp->xsize*8)
604 		scp->mouse_xpos = (scp->xsize*8)-1;
605 	    if (scp->mouse_ypos >= scp->ysize*fontsize)
606 		scp->mouse_ypos = (scp->ysize*fontsize)-1;
607 	    scp->mouse_pos = scp->scr_buf +
608 		(scp->mouse_ypos/fontsize)*scp->xsize + scp->mouse_xpos/8;
609 	    if (scp->status & MOUSE_ENABLED)
610 		scp->status |= UPDATE_MOUSE;
611 	    break;
612 
613 	case MOUSE_GETPOS:
614 	    mouse->x = scp->mouse_xpos;
615 	    mouse->y = scp->mouse_ypos;
616 	    return 0;
617 
618 	default:
619 	    return EINVAL;
620 	}
621 	/* make screensaver happy */
622 	if (scp == cur_console) {
623 	    scrn_time_stamp = time.tv_sec;
624 	    if (scrn_blanked) {
625 		(*current_saver)(FALSE);
626 		cur_console->start = 0;
627 		cur_console->end = cur_console->xsize * cur_console->ysize;
628 	    }
629 	}
630 	return 0;
631     }
632 
633     case CONS_GETINFO:  	/* get current (virtual) console info */
634     {
635 	vid_info_t *ptr = (vid_info_t*)data;
636 	if (ptr->size == sizeof(struct vid_info)) {
637 	    ptr->m_num = get_scr_num();
638 	    ptr->mv_col = scp->xpos;
639 	    ptr->mv_row = scp->ypos;
640 	    ptr->mv_csz = scp->xsize;
641 	    ptr->mv_rsz = scp->ysize;
642 	    ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
643 	    ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
644 	    ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
645 	    ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
646 	    ptr->mv_grfc.fore = 0;      /* not supported */
647 	    ptr->mv_grfc.back = 0;      /* not supported */
648 	    ptr->mv_ovscan = scp->border;
649 	    ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
650 	    return 0;
651 	}
652 	return EINVAL;
653     }
654 
655     case CONS_GETVERS:  	/* get version number */
656 	*(int*)data = 0x200;    /* version 2.0 */
657 	return 0;
658 
659     /* VGA TEXT MODES */
660     case SW_VGA_C40x25:
661     case SW_VGA_C80x25: case SW_VGA_M80x25:
662     case SW_VGA_C80x30: case SW_VGA_M80x30:
663     case SW_VGA_C80x50: case SW_VGA_M80x50:
664     case SW_VGA_C80x60: case SW_VGA_M80x60:
665     case SW_B40x25:     case SW_C40x25:
666     case SW_B80x25:     case SW_C80x25:
667     case SW_ENH_B40x25: case SW_ENH_C40x25:
668     case SW_ENH_B80x25: case SW_ENH_C80x25:
669     case SW_ENH_B80x43: case SW_ENH_C80x43:
670 
671 	if (!crtc_vga || video_mode_ptr == NULL)
672 	    return ENXIO;
673 	switch (cmd & 0xff) {
674 	case M_VGA_C80x60: case M_VGA_M80x60:
675 	    if (!(fonts_loaded & FONT_8))
676 		return EINVAL;
677 	    scp->xsize = 80;
678 	    scp->ysize = 60;
679 	    break;
680 	case M_VGA_C80x50: case M_VGA_M80x50:
681 	    if (!(fonts_loaded & FONT_8))
682 		return EINVAL;
683 	    scp->xsize = 80;
684 	    scp->ysize = 50;
685 	    break;
686 	case M_ENH_B80x43: case M_ENH_C80x43:
687 	    if (!(fonts_loaded & FONT_8))
688 		return EINVAL;
689 	    scp->xsize = 80;
690 	    scp->ysize = 43;
691 	    break;
692 	case M_VGA_C80x30: case M_VGA_M80x30:
693 	    scp->xsize = 80;
694 	    scp->ysize = 30;
695 	    break;
696 	default:
697 	    if ((cmd & 0xff) > M_VGA_CG320)
698 		return EINVAL;
699 	    else
700 		scp->xsize = *(video_mode_ptr+((cmd&0xff)*64));
701 		scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1;
702 	    break;
703 	}
704 	scp->mode = cmd & 0xff;
705 	scp->status &= ~UNKNOWN_MODE;   /* text mode */
706 	free(scp->scr_buf, M_DEVBUF);
707 	scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
708 					 M_DEVBUF, M_NOWAIT);
709 	if (scp == cur_console)
710 	    set_mode(scp);
711 	clear_screen(scp);
712 	if (tp->t_winsize.ws_col != scp->xsize
713 	    || tp->t_winsize.ws_row != scp->ysize) {
714 	    tp->t_winsize.ws_col = scp->xsize;
715 	    tp->t_winsize.ws_row = scp->ysize;
716 	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
717 	}
718 	return 0;
719 
720     /* GRAPHICS MODES */
721     case SW_BG320:     case SW_BG640:
722     case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
723     case SW_CG640x350: case SW_ENH_CG640:
724     case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
725 
726 	if (!crtc_vga || video_mode_ptr == NULL)
727 	    return ENXIO;
728 	scp->mode = cmd & 0xFF;
729 	scp->status |= UNKNOWN_MODE;    /* graphics mode */
730 	scp->xsize = (*(video_mode_ptr + (scp->mode*64))) * 8;
731 	scp->ysize = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) *
732 		     (*(video_mode_ptr + (scp->mode*64) + 2));
733 	set_mode(scp);
734 	/* clear_graphics();*/
735 
736 	if (tp->t_winsize.ws_xpixel != scp->xsize
737 	    || tp->t_winsize.ws_ypixel != scp->ysize) {
738 	    tp->t_winsize.ws_xpixel = scp->xsize;
739 	    tp->t_winsize.ws_ypixel = scp->ysize;
740 	    pgsignal(tp->t_pgrp, SIGWINCH, 1);
741 	}
742 	return 0;
743 
744     case VT_SETMODE:    	/* set screen switcher mode */
745 	bcopy(data, &scp->smode, sizeof(struct vt_mode));
746 	if (scp->smode.mode == VT_PROCESS) {
747 	    scp->proc = p;
748 	    scp->pid = scp->proc->p_pid;
749 	}
750 	return 0;
751 
752     case VT_GETMODE:    	/* get screen switcher mode */
753 	bcopy(&scp->smode, data, sizeof(struct vt_mode));
754 	return 0;
755 
756     case VT_RELDISP:    	/* screen switcher ioctl */
757 	switch(*data) {
758 	case VT_FALSE:  	/* user refuses to release screen, abort */
759 	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
760 		old_scp->status &= ~SWITCH_WAIT_REL;
761 		switch_in_progress = FALSE;
762 		return 0;
763 	    }
764 	    return EINVAL;
765 
766 	case VT_TRUE:   	/* user has released screen, go on */
767 	    if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
768 		scp->status &= ~SWITCH_WAIT_REL;
769 		exchange_scr();
770 		if (new_scp->smode.mode == VT_PROCESS) {
771 		    new_scp->status |= SWITCH_WAIT_ACQ;
772 		    psignal(new_scp->proc, new_scp->smode.acqsig);
773 		}
774 		else
775 		    switch_in_progress = FALSE;
776 		return 0;
777 	    }
778 	    return EINVAL;
779 
780 	case VT_ACKACQ: 	/* acquire acknowledged, switch completed */
781 	    if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
782 		scp->status &= ~SWITCH_WAIT_ACQ;
783 		switch_in_progress = FALSE;
784 		return 0;
785 	    }
786 	    return EINVAL;
787 
788 	default:
789 	    return EINVAL;
790 	}
791 	/* NOT REACHED */
792 
793     case VT_OPENQRY:    	/* return free virtual console */
794 	for (i = 0; i < MAXCONS; i++) {
795 	    tp = VIRTUAL_TTY(i);
796 	    if (!(tp->t_state & TS_ISOPEN)) {
797 		*data = i + 1;
798 		return 0;
799 	    }
800 	}
801 	return EINVAL;
802 
803     case VT_ACTIVATE:   	/* switch to screen *data */
804 	return switch_scr(scp, (*data) - 1);
805 
806     case VT_WAITACTIVE: 	/* wait for switch to occur */
807 	if (*data > MAXCONS || *data < 0)
808 	    return EINVAL;
809 	if (minor(dev) == (*data) - 1)
810 	    return 0;
811 	if (*data == 0) {
812 	    if (scp == cur_console)
813 		return 0;
814 	}
815 	else
816 	    scp = console[(*data) - 1];
817 	while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
818 			     "waitvt", 0)) == ERESTART) ;
819 	return error;
820 
821     case VT_GETACTIVE:
822 	*data = get_scr_num()+1;
823 	return 0;
824 
825     case KDENABIO:      	/* allow io operations */
826 	fp = (struct trapframe *)p->p_md.md_regs;
827 	fp->tf_eflags |= PSL_IOPL;
828 	return 0;
829 
830     case KDDISABIO:     	/* disallow io operations (default) */
831 	fp = (struct trapframe *)p->p_md.md_regs;
832 	fp->tf_eflags &= ~PSL_IOPL;
833 	return 0;
834 
835     case KDSETMODE:     	/* set current mode of this (virtual) console */
836 	switch (*data) {
837 	case KD_TEXT:   	/* switch to TEXT (known) mode */
838 	    /* restore fonts & palette ! */
839 	    if (crtc_vga) {
840 		if (fonts_loaded & FONT_8)
841 		    copy_font(LOAD, FONT_8, font_8);
842 		if (fonts_loaded & FONT_14)
843 		    copy_font(LOAD, FONT_14, font_14);
844 		if (fonts_loaded & FONT_16)
845 		    copy_font(LOAD, FONT_16, font_16);
846 		if (configuration & CHAR_CURSOR)
847 		    set_destructive_cursor(scp, TRUE);
848 		load_palette();
849 	    }
850 	    /* FALL THROUGH */
851 
852 	case KD_TEXT1:  	/* switch to TEXT (known) mode */
853 	    /* no restore fonts & palette */
854 	    scp->status &= ~UNKNOWN_MODE;
855 	    if (crtc_vga && video_mode_ptr)
856 		set_mode(scp);
857 	    clear_screen(scp);
858 	    return 0;
859 
860 	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
861 	    scp->status |= UNKNOWN_MODE;
862 	    return 0;
863 	default:
864 	    return EINVAL;
865 	}
866 	/* NOT REACHED */
867 
868     case KDGETMODE:     	/* get current mode of this (virtual) console */
869 	*data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
870 	return 0;
871 
872     case KDSBORDER:     	/* set border color of this (virtual) console */
873 	if (!crtc_vga)
874 	    return ENXIO;
875 	scp->border = *data;
876 	if (scp == cur_console)
877 	    set_border(scp->border);
878 	return 0;
879 
880     case KDSKBSTATE:    	/* set keyboard state (locks) */
881 	if (*data >= 0 && *data <= LOCK_KEY_MASK) {
882 	    scp->status &= ~LOCK_KEY_MASK;
883 	    scp->status |= *data;
884 	    if (scp == cur_console)
885 		update_leds(scp->status);
886 	    return 0;
887 	}
888 	return EINVAL;
889 
890     case KDGKBSTATE:    	/* get keyboard state (locks) */
891 	*data = scp->status & LOCK_KEY_MASK;
892 	return 0;
893 
894     case KDSETRAD:      	/* set keyboard repeat & delay rates */
895 	if (*data & 0x80)
896 	    return EINVAL;
897 	i = spltty();
898 	kbd_cmd(KB_SETRAD);
899 	kbd_cmd(*data);
900 	splx(i);
901 	return 0;
902 
903     case KDSKBMODE:     	/* set keyboard mode */
904 	switch (*data) {
905 	case K_RAW: 		/* switch to RAW scancode mode */
906 	    scp->status |= KBD_RAW_MODE;
907 	    return 0;
908 
909 	case K_XLATE:   	/* switch to XLT ascii mode */
910 	    if (scp == cur_console && scp->status == KBD_RAW_MODE)
911 		shfts = ctls = alts = agrs = metas = 0;
912 	    scp->status &= ~KBD_RAW_MODE;
913 	    return 0;
914 	default:
915 	    return EINVAL;
916 	}
917 	/* NOT REACHED */
918 
919     case KDGKBMODE:     	/* get keyboard mode */
920 	*data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
921 	return 0;
922 
923     case KDMKTONE:      	/* sound the bell */
924 	if (*(int*)data)
925 	    do_bell(scp, (*(int*)data)&0xffff,
926 		    (((*(int*)data)>>16)&0xffff)*hz/1000);
927 	else
928 	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
929 	return 0;
930 
931     case KIOCSOUND:     	/* make tone (*data) hz */
932 	if (scp == cur_console) {
933 	    if (*(int*)data) {
934 		int pitch = TIMER_FREQ/(*(int*)data);
935 
936 		/* set command for counter 2, 2 byte write */
937 		if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
938 		    return EBUSY;
939 
940 		/* set pitch */
941 		outb(TIMER_CNTR2, pitch);
942 		outb(TIMER_CNTR2, (pitch>>8));
943 
944 		/* enable counter 2 output to speaker */
945 		outb(IO_PPI, inb(IO_PPI) | 3);
946 	    }
947 	    else {
948 		/* disable counter 2 output to speaker */
949 		outb(IO_PPI, inb(IO_PPI) & 0xFC);
950 		release_timer2();
951 	    }
952 	}
953 	return 0;
954 
955     case KDGKBTYPE:     	/* get keyboard type */
956 	*data = 0;  		/* type not known (yet) */
957 	return 0;
958 
959     case KDSETLED:      	/* set keyboard LED status */
960 	if (*data >= 0 && *data <= LED_MASK) {
961 	    scp->status &= ~LED_MASK;
962 	    scp->status |= *data;
963 	    if (scp == cur_console)
964 		update_leds(scp->status);
965 	    return 0;
966 	}
967 	return EINVAL;
968 
969     case KDGETLED:      	/* get keyboard LED status */
970 	*data = scp->status & LED_MASK;
971 	return 0;
972 
973     case GETFKEY:       	/* get functionkey string */
974 	if (*(u_short*)data < n_fkey_tab) {
975 	    fkeyarg_t *ptr = (fkeyarg_t*)data;
976 	    bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
977 		  fkey_tab[ptr->keynum].len);
978 	    ptr->flen = fkey_tab[ptr->keynum].len;
979 	    return 0;
980 	}
981 	else
982 	    return EINVAL;
983 
984     case SETFKEY:       	/* set functionkey string */
985 	if (*(u_short*)data < n_fkey_tab) {
986 	    fkeyarg_t *ptr = (fkeyarg_t*)data;
987 	    bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
988 		  min(ptr->flen, MAXFK));
989 	    fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
990 	    return 0;
991 	}
992 	else
993 	    return EINVAL;
994 
995     case GIO_SCRNMAP:   	/* get output translation table */
996 	bcopy(&scr_map, data, sizeof(scr_map));
997 	return 0;
998 
999     case PIO_SCRNMAP:   	/* set output translation table */
1000 	bcopy(data, &scr_map, sizeof(scr_map));
1001 	return 0;
1002 
1003     case GIO_KEYMAP:    	/* get keyboard translation table */
1004 	bcopy(&key_map, data, sizeof(key_map));
1005 	return 0;
1006 
1007     case PIO_KEYMAP:    	/* set keyboard translation table */
1008 	bcopy(data, &key_map, sizeof(key_map));
1009 	return 0;
1010 
1011     case PIO_FONT8x8:   	/* set 8x8 dot font */
1012 	if (!crtc_vga)
1013 	    return ENXIO;
1014 	bcopy(data, font_8, 8*256);
1015 	fonts_loaded |= FONT_8;
1016 	copy_font(LOAD, FONT_8, font_8);
1017 	if (configuration & CHAR_CURSOR)
1018 	    set_destructive_cursor(scp, TRUE);
1019 	return 0;
1020 
1021     case GIO_FONT8x8:   	/* get 8x8 dot font */
1022 	if (!crtc_vga)
1023 	    return ENXIO;
1024 	if (fonts_loaded & FONT_8) {
1025 	    bcopy(font_8, data, 8*256);
1026 	    return 0;
1027 	}
1028 	else
1029 	    return ENXIO;
1030 
1031     case PIO_FONT8x14:  	/* set 8x14 dot font */
1032 	if (!crtc_vga)
1033 	    return ENXIO;
1034 	bcopy(data, font_14, 14*256);
1035 	fonts_loaded |= FONT_14;
1036 	copy_font(LOAD, FONT_14, font_14);
1037 	if (configuration & CHAR_CURSOR)
1038 	    set_destructive_cursor(scp, TRUE);
1039 	return 0;
1040 
1041     case GIO_FONT8x14:  	/* get 8x14 dot font */
1042 	if (!crtc_vga)
1043 	    return ENXIO;
1044 	if (fonts_loaded & FONT_14) {
1045 	    bcopy(font_14, data, 14*256);
1046 	    return 0;
1047 	}
1048 	else
1049 	    return ENXIO;
1050 
1051     case PIO_FONT8x16:  	/* set 8x16 dot font */
1052 	if (!crtc_vga)
1053 	    return ENXIO;
1054 	bcopy(data, font_16, 16*256);
1055 	fonts_loaded |= FONT_16;
1056 	copy_font(LOAD, FONT_16, font_16);
1057 	if (configuration & CHAR_CURSOR)
1058 	    set_destructive_cursor(scp, TRUE);
1059 	return 0;
1060 
1061     case GIO_FONT8x16:  	/* get 8x16 dot font */
1062 	if (!crtc_vga)
1063 	    return ENXIO;
1064 	if (fonts_loaded & FONT_16) {
1065 	    bcopy(font_16, data, 16*256);
1066 	    return 0;
1067 	}
1068 	else
1069 	    return ENXIO;
1070     default:
1071 	break;
1072     }
1073 
1074     error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1075     if (error >= 0)
1076 	return(error);
1077     error = ttioctl(tp, cmd, data, flag);
1078     if (error >= 0)
1079 	return(error);
1080     return(ENOTTY);
1081 }
1082 
1083 void
1084 scxint(dev_t dev)
1085 {
1086     struct tty *tp = scdevtotty(dev);
1087 
1088     if (!tp)
1089 	return;
1090     tp->t_state &= ~TS_BUSY;
1091     if (tp->t_line)
1092 	(*linesw[tp->t_line].l_start)(tp);
1093     else
1094 	scstart(tp);
1095 }
1096 
1097 void
1098 scstart(struct tty *tp)
1099 {
1100     struct clist *rbp;
1101     int i, s, len;
1102     u_char buf[PCBURST];
1103     scr_stat *scp = get_scr_stat(tp->t_dev);
1104 
1105     if (scp->status & SLKED || blink_in_progress)
1106 	return;
1107     s = spltty();
1108     if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
1109 	tp->t_state |= TS_BUSY;
1110 	splx(s);
1111 	rbp = &tp->t_outq;
1112 	while (rbp->c_cc) {
1113 	    len = q_to_b(rbp, buf, PCBURST);
1114 	    ansi_put(scp, buf, len);
1115 	}
1116 	s = spltty();
1117 	tp->t_state &= ~TS_BUSY;
1118 	if (rbp->c_cc <= tp->t_lowat) {
1119 	    if (tp->t_state & TS_ASLEEP) {
1120 		tp->t_state &= ~TS_ASLEEP;
1121 		wakeup((caddr_t)rbp);
1122 	    }
1123 	    selwakeup(&tp->t_wsel);
1124 	}
1125     }
1126     splx(s);
1127 }
1128 
1129 void
1130 pccnprobe(struct consdev *cp)
1131 {
1132     int maj;
1133 
1134     /* locate the major number */
1135     for (maj = 0; maj < nchrdev; maj++)
1136 	if ((void*)cdevsw[maj].d_open == (void*)scopen)
1137 	    break;
1138 
1139     /* initialize required fields */
1140     cp->cn_dev = makedev(maj, MAXCONS);
1141     cp->cn_pri = CN_INTERNAL;
1142 }
1143 
1144 void
1145 pccninit(struct consdev *cp)
1146 {
1147     scinit();
1148 }
1149 
1150 void
1151 pccnputc(dev_t dev, int c)
1152 {
1153     u_char buf[1];
1154     scr_stat *scp = console[0];
1155     term_stat save = scp->term;
1156 
1157     scp->term = kernel_console;
1158     current_default = &kernel_default;
1159     if (scp->scr_buf == Crtat)
1160 	draw_cursor(scp, FALSE);
1161     if (c == '\n')
1162 	ansi_put(scp, "\r\n", 2);
1163     else {
1164 	buf[0] = c;
1165 	ansi_put(scp, buf, 1);
1166     }
1167     kernel_console = scp->term;
1168     current_default = &user_default;
1169     scp->term = save;
1170     if (scp == cur_console /* && scrn_timer not running */) {
1171 	if (scp->scr_buf != Crtat && (scp->start <= scp->end)) {
1172 	    bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1173 		   (1 + scp->end - scp->start) * sizeof(u_short));
1174 	    scp->start = scp->xsize * scp->ysize;
1175 	    scp->end = 0;
1176 	    scp->status &= ~CURSOR_SHOWN;
1177 	}
1178 	draw_cursor(scp, TRUE);
1179     }
1180 }
1181 
1182 int
1183 pccngetc(dev_t dev)
1184 {
1185     int s = spltty();       /* block scintr while we poll */
1186     int c = scgetc(0);
1187     splx(s);
1188     return(c);
1189 }
1190 
1191 int
1192 pccncheckc(dev_t dev)
1193 {
1194     return (scgetc(1) & 0xff);
1195 }
1196 
1197 static void
1198 scrn_timer()
1199 {
1200     static int cursor_blinkrate;
1201     scr_stat *scp = cur_console;
1202 
1203     /* should we just return ? */
1204     if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
1205 	timeout((timeout_func_t)scrn_timer, 0, hz/10);
1206 	return;
1207     }
1208 
1209     if (!scrn_blanked) {
1210 	/* update screen image */
1211 	if (scp->start <= scp->end) {
1212 	    bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1213 		   (1 + scp->end - scp->start) * sizeof(u_short));
1214 	    scp->status &= ~CURSOR_SHOWN;
1215 	    scp->start = scp->xsize * scp->ysize;
1216 	    scp->end = 0;
1217 	}
1218 	/* update "pseudo" mouse arrow */
1219 	if ((scp->status & MOUSE_ENABLED) && (scp->status & UPDATE_MOUSE))
1220 	    draw_mouse_image(scp);
1221 
1222 	/* update cursor image */
1223 	if (scp->status & CURSOR_ENABLED)
1224 	    draw_cursor(scp,
1225 		!(configuration&BLINK_CURSOR) || !(cursor_blinkrate++&0x04));
1226     }
1227     if (scrn_blank_time && (time.tv_sec>scrn_time_stamp+scrn_blank_time))
1228 	(*current_saver)(TRUE);
1229     timeout((timeout_func_t)scrn_timer, 0, hz/25);
1230 }
1231 
1232 static void
1233 clear_screen(scr_stat *scp)
1234 {
1235     move_crsr(scp, 0, 0);
1236     fillw(scp->term.cur_attr | scr_map[0x20], scp->scr_buf,
1237 	  scp->xsize * scp->ysize);
1238     mark_all(scp);
1239 }
1240 
1241 static int
1242 switch_scr(scr_stat *scp, u_int next_scr)
1243 {
1244     if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
1245 	switch_in_progress = FALSE;
1246 
1247     if (next_scr >= MAXCONS || switch_in_progress ||
1248 	(cur_console->smode.mode == VT_AUTO
1249 	 && cur_console->status & UNKNOWN_MODE)) {
1250 	do_bell(scp, BELL_PITCH, BELL_DURATION);
1251 	return EINVAL;
1252     }
1253 
1254     /* is the wanted virtual console open ? */
1255     if (next_scr) {
1256 	struct tty *tp = VIRTUAL_TTY(next_scr);
1257 	if (!(tp->t_state & TS_ISOPEN)) {
1258 	    do_bell(scp, BELL_PITCH, BELL_DURATION);
1259 	    return EINVAL;
1260 	}
1261     }
1262     /* delay switch if actively updating screen */
1263     if (write_in_progress || blink_in_progress) {
1264 	delayed_next_scr = next_scr+1;
1265 	return 0;
1266     }
1267     switch_in_progress = TRUE;
1268     old_scp = cur_console;
1269     new_scp = console[next_scr];
1270     wakeup((caddr_t)&new_scp->smode);
1271     if (new_scp == old_scp) {
1272 	switch_in_progress = FALSE;
1273 	delayed_next_scr = FALSE;
1274 	return 0;
1275     }
1276 
1277     /* has controlling process died? */
1278     if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
1279 	old_scp->smode.mode = VT_AUTO;
1280     if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
1281 	new_scp->smode.mode = VT_AUTO;
1282 
1283     /* check the modes and switch approbiatly */
1284     if (old_scp->smode.mode == VT_PROCESS) {
1285 	old_scp->status |= SWITCH_WAIT_REL;
1286 	psignal(old_scp->proc, old_scp->smode.relsig);
1287     }
1288     else {
1289 	exchange_scr();
1290 	if (new_scp->smode.mode == VT_PROCESS) {
1291 	    new_scp->status |= SWITCH_WAIT_ACQ;
1292 	    psignal(new_scp->proc, new_scp->smode.acqsig);
1293 	}
1294 	else
1295 	    switch_in_progress = FALSE;
1296     }
1297     return 0;
1298 }
1299 
1300 static void
1301 exchange_scr(void)
1302 {
1303     move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
1304     cur_console = new_scp;
1305     if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
1306 	if (crtc_vga && video_mode_ptr)
1307 	    set_mode(new_scp);
1308     }
1309     move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
1310     if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
1311 	if (fonts_loaded & FONT_8)
1312 	    copy_font(LOAD, FONT_8, font_8);
1313 	if (fonts_loaded & FONT_14)
1314 	    copy_font(LOAD, FONT_14, font_14);
1315 	if (fonts_loaded & FONT_16)
1316 	    copy_font(LOAD, FONT_16, font_16);
1317 	if (configuration & CHAR_CURSOR)
1318 	    set_destructive_cursor(new_scp, TRUE);
1319 	load_palette();
1320     }
1321     if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
1322 	shfts = ctls = alts = agrs = metas = 0;
1323     update_leds(new_scp->status);
1324     delayed_next_scr = FALSE;
1325     bcopyw(new_scp->scr_buf, Crtat,
1326 	   (new_scp->xsize*new_scp->ysize)*sizeof(u_short));
1327     new_scp->status &= ~CURSOR_SHOWN;
1328 }
1329 
1330 static inline void
1331 move_crsr(scr_stat *scp, int x, int y)
1332 {
1333     if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
1334 	return;
1335     scp->xpos = x;
1336     scp->ypos = y;
1337     mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1338     scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
1339     mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1340 }
1341 
1342 static void
1343 scan_esc(scr_stat *scp, u_char c)
1344 {
1345     static u_char ansi_col[16] =
1346 	{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
1347     int i, n;
1348     u_short *src, *dst, count;
1349 
1350     if (scp->term.esc == 1) {
1351 	switch (c) {
1352 
1353 	case '[':   /* Start ESC [ sequence */
1354 	    scp->term.esc = 2;
1355 	    scp->term.last_param = -1;
1356 	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1357 		scp->term.param[i] = 1;
1358 	    scp->term.num_param = 0;
1359 	    return;
1360 
1361 	case 'M':   /* Move cursor up 1 line, scroll if at top */
1362 	    if (scp->ypos > 0)
1363 		move_crsr(scp, scp->xpos, scp->ypos - 1);
1364 	    else {
1365 		bcopyw(scp->scr_buf, scp->scr_buf + scp->xsize,
1366 		       (scp->ysize - 1) * scp->xsize * sizeof(u_short));
1367 		fillw(scp->term.cur_attr | scr_map[0x20],
1368 		      scp->scr_buf, scp->xsize);
1369     		mark_all(scp);
1370 	    }
1371 	    break;
1372 #if notyet
1373 	case 'Q':
1374 	    scp->term.esc = 4;
1375 	    break;
1376 #endif
1377 	case 'c':   /* Clear screen & home */
1378 	    clear_screen(scp);
1379 	    break;
1380 	}
1381     }
1382     else if (scp->term.esc == 2) {
1383 	if (c >= '0' && c <= '9') {
1384 	    if (scp->term.num_param < MAX_ESC_PAR) {
1385 	    if (scp->term.last_param != scp->term.num_param) {
1386 		scp->term.last_param = scp->term.num_param;
1387 		scp->term.param[scp->term.num_param] = 0;
1388 	    }
1389 	    else
1390 		scp->term.param[scp->term.num_param] *= 10;
1391 	    scp->term.param[scp->term.num_param] += c - '0';
1392 	    return;
1393 	    }
1394 	}
1395 	scp->term.num_param = scp->term.last_param + 1;
1396 	switch (c) {
1397 
1398 	case ';':
1399 	    if (scp->term.num_param < MAX_ESC_PAR)
1400 		return;
1401 	    break;
1402 
1403 	case '=':
1404 	    scp->term.esc = 3;
1405 	    scp->term.last_param = -1;
1406 	    for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1407 		scp->term.param[i] = 1;
1408 	    scp->term.num_param = 0;
1409 	    return;
1410 
1411 	case 'A':   /* up n rows */
1412 	    n = scp->term.param[0]; if (n < 1) n = 1;
1413 	    move_crsr(scp, scp->xpos, scp->ypos - n);
1414 	    break;
1415 
1416 	case 'B':   /* down n rows */
1417 	    n = scp->term.param[0]; if (n < 1) n = 1;
1418 	    move_crsr(scp, scp->xpos, scp->ypos + n);
1419 	    break;
1420 
1421 	case 'C':   /* right n columns */
1422 	    n = scp->term.param[0]; if (n < 1) n = 1;
1423 	    move_crsr(scp, scp->xpos + n, scp->ypos);
1424 	    break;
1425 
1426 	case 'D':   /* left n columns */
1427 	    n = scp->term.param[0]; if (n < 1) n = 1;
1428 	    move_crsr(scp, scp->xpos - n, scp->ypos);
1429 	    break;
1430 
1431 	case 'E':   /* cursor to start of line n lines down */
1432 	    n = scp->term.param[0]; if (n < 1) n = 1;
1433 	    move_crsr(scp, 0, scp->ypos + n);
1434 	    break;
1435 
1436 	case 'F':   /* cursor to start of line n lines up */
1437 	    n = scp->term.param[0]; if (n < 1) n = 1;
1438 	    move_crsr(scp, 0, scp->ypos - n);
1439 	    break;
1440 
1441 	case 'f':   /* Cursor move */
1442 	case 'H':
1443 	    if (scp->term.num_param == 0)
1444 		move_crsr(scp, 0, 0);
1445 	    else if (scp->term.num_param == 2)
1446 		move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
1447 	    break;
1448 
1449 	case 'J':   /* Clear all or part of display */
1450 	    if (scp->term.num_param == 0)
1451 		n = 0;
1452 	    else
1453 		n = scp->term.param[0];
1454 	    switch (n) {
1455 	    case 0: /* clear form cursor to end of display */
1456 		fillw(scp->term.cur_attr | scr_map[0x20],
1457 		      scp->cursor_pos,
1458 		      scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
1459     		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1460     		mark_for_update(scp, scp->xsize * scp->ysize);
1461 		break;
1462 	    case 1: /* clear from beginning of display to cursor */
1463 		fillw(scp->term.cur_attr | scr_map[0x20],
1464 		      scp->scr_buf,
1465 		      scp->cursor_pos - scp->scr_buf);
1466     		mark_for_update(scp, 0);
1467     		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1468 		break;
1469 	    case 2: /* clear entire display */
1470 		clear_screen(scp);
1471 		break;
1472 	    }
1473 	    break;
1474 
1475 	case 'K':   /* Clear all or part of line */
1476 	    if (scp->term.num_param == 0)
1477 		n = 0;
1478 	    else
1479 		n = scp->term.param[0];
1480 	    switch (n) {
1481 	    case 0: /* clear form cursor to end of line */
1482 		fillw(scp->term.cur_attr | scr_map[0x20],
1483 		      scp->cursor_pos,
1484 		      scp->xsize - scp->xpos);
1485     		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1486     		mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
1487 				scp->xsize - scp->xpos);
1488 		break;
1489 	    case 1: /* clear from beginning of line to cursor */
1490 		fillw(scp->term.cur_attr|scr_map[0x20],
1491 		      scp->cursor_pos - (scp->xsize - scp->xpos),
1492 		      (scp->xsize - scp->xpos) + 1);
1493     		mark_for_update(scp, scp->ypos * scp->xsize);
1494     		mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1495 		break;
1496 	    case 2: /* clear entire line */
1497 		fillw(scp->term.cur_attr|scr_map[0x20],
1498 		      scp->cursor_pos - (scp->xsize - scp->xpos),
1499 		      scp->xsize);
1500     		mark_for_update(scp, scp->ypos * scp->xsize);
1501     		mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
1502 		break;
1503 	    }
1504 	    break;
1505 
1506 	case 'L':   /* Insert n lines */
1507 	    n = scp->term.param[0]; if (n < 1) n = 1;
1508 	    if (n > scp->ysize - scp->ypos)
1509 		n = scp->ysize - scp->ypos;
1510 	    src = scp->scr_buf + scp->ypos * scp->xsize;
1511 	    dst = src + n * scp->xsize;
1512 	    count = scp->ysize - (scp->ypos + n);
1513 	    bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1514 	    fillw(scp->term.cur_attr | scr_map[0x20], src,
1515 		  n * scp->xsize);
1516 	    mark_for_update(scp, scp->ypos * scp->xsize);
1517 	    mark_for_update(scp, scp->xsize * scp->ysize);
1518 	    break;
1519 
1520 	case 'M':   /* Delete n lines */
1521 	    n = scp->term.param[0]; if (n < 1) n = 1;
1522 	    if (n > scp->ysize - scp->ypos)
1523 		n = scp->ysize - scp->ypos;
1524 	    dst = scp->scr_buf + scp->ypos * scp->xsize;
1525 	    src = dst + n * scp->xsize;
1526 	    count = scp->ysize - (scp->ypos + n);
1527 	    bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1528 	    src = dst + count * scp->xsize;
1529 	    fillw(scp->term.cur_attr | scr_map[0x20], src,
1530 		  n * scp->xsize);
1531 	    mark_for_update(scp, scp->ypos * scp->xsize);
1532 	    mark_for_update(scp, scp->xsize * scp->ysize);
1533 	    break;
1534 
1535 	case 'P':   /* Delete n chars */
1536 	    n = scp->term.param[0]; if (n < 1) n = 1;
1537 	    if (n > scp->xsize - scp->xpos)
1538 		n = scp->xsize - scp->xpos;
1539 	    dst = scp->cursor_pos;
1540 	    src = dst + n;
1541 	    count = scp->xsize - (scp->xpos + n);
1542 	    bcopyw(src, dst, count * sizeof(u_short));
1543 	    src = dst + count;
1544 	    fillw(scp->term.cur_attr | scr_map[0x20], src, n);
1545 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1546 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1547 	    break;
1548 
1549 	case '@':   /* Insert n chars */
1550 	    n = scp->term.param[0]; if (n < 1) n = 1;
1551 	    if (n > scp->xsize - scp->xpos)
1552 		n = scp->xsize - scp->xpos;
1553 	    src = scp->cursor_pos;
1554 	    dst = src + n;
1555 	    count = scp->xsize - (scp->xpos + n);
1556 	    bcopyw(src, dst, count * sizeof(u_short));
1557 	    fillw(scp->term.cur_attr | scr_map[0x20], src, n);
1558 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1559 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1560 	    break;
1561 
1562 	case 'S':   /* scroll up n lines */
1563 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1564 	    if (n > scp->ysize)
1565 		n = scp->ysize;
1566 	    bcopyw(scp->scr_buf + (scp->xsize * n),
1567 		   scp->scr_buf,
1568 		   scp->xsize * (scp->ysize - n) * sizeof(u_short));
1569 	    fillw(scp->term.cur_attr | scr_map[0x20],
1570 		  scp->scr_buf + scp->xsize * (scp->ysize - n),
1571 		  scp->xsize * n);
1572     	    mark_all(scp);
1573 	    break;
1574 
1575 	case 'T':   /* scroll down n lines */
1576 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1577 	    if (n > scp->ysize)
1578 		n = scp->ysize;
1579 	    bcopyw(scp->scr_buf,
1580 		  scp->scr_buf + (scp->xsize * n),
1581 		  scp->xsize * (scp->ysize - n) *
1582 		  sizeof(u_short));
1583 	    fillw(scp->term.cur_attr | scr_map[0x20],
1584 		  scp->scr_buf, scp->xsize * n);
1585     	    mark_all(scp);
1586 	    break;
1587 
1588 	case 'X':   /* erase n characters in line */
1589 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1590 	    if (n > scp->xsize - scp->xpos)
1591 		n = scp->xsize - scp->xpos;
1592 	    fillw(scp->term.cur_attr | scr_map[0x20],
1593 		  scp->scr_buf + scp->xpos +
1594 		  ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
1595 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1596 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
1597 	    break;
1598 
1599 	case 'Z':   /* move n tabs backwards */
1600 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1601 	    if ((i = scp->xpos & 0xf8) == scp->xpos)
1602 		i -= 8*n;
1603 	    else
1604 		i -= 8*(n-1);
1605 	    if (i < 0)
1606 		i = 0;
1607 	    move_crsr(scp, i, scp->ypos);
1608 	    break;
1609 
1610 	case '`':   /* move cursor to column n */
1611 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1612 	    move_crsr(scp, n - 1, scp->ypos);
1613 	    break;
1614 
1615 	case 'a':   /* move cursor n columns to the right */
1616 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1617 	    move_crsr(scp, scp->xpos + n, scp->ypos);
1618 	    break;
1619 
1620 	case 'd':   /* move cursor to row n */
1621 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1622 	    move_crsr(scp, scp->xpos, n - 1);
1623 	    break;
1624 
1625 	case 'e':   /* move cursor n rows down */
1626 	    n = scp->term.param[0]; if (n < 1)  n = 1;
1627 	    move_crsr(scp, scp->xpos, scp->ypos + n);
1628 	    break;
1629 
1630 	case 'm':   /* change attribute */
1631 	    if (scp->term.num_param == 0) {
1632 		scp->term.cur_attr = scp->term.std_attr;
1633 		break;
1634 	    }
1635 	    for (i = 0; i < scp->term.num_param; i++) {
1636 		switch (n = scp->term.param[i]) {
1637 		case 0: /* back to normal */
1638 		    scp->term.cur_attr = scp->term.std_attr;
1639 		    break;
1640 		case 1: /* highlight (bold) */
1641 		    scp->term.cur_attr &= 0xFF00;
1642 		    scp->term.cur_attr |= 0x0800;
1643 		    break;
1644 		case 4: /* highlight (underline) */
1645 		    scp->term.cur_attr &= 0xFF00;
1646 		    scp->term.cur_attr |= 0x0800;
1647 		    break;
1648 		case 5: /* blink */
1649 		    scp->term.cur_attr &= 0xFF00;
1650 		    scp->term.cur_attr |= 0x8000;
1651 		    break;
1652 		case 7: /* reverse video */
1653 		    scp->term.cur_attr = scp->term.rev_attr;
1654 		    break;
1655 		case 30: case 31: /* set fg color */
1656 		case 32: case 33: case 34:
1657 		case 35: case 36: case 37:
1658 		    scp->term.cur_attr =
1659 			(scp->term.cur_attr&0xF8FF) | (ansi_col[(n-30)&7]<<8);
1660 		    break;
1661 		case 40: case 41: /* set bg color */
1662 		case 42: case 43: case 44:
1663 		case 45: case 46: case 47:
1664 		    scp->term.cur_attr =
1665 			(scp->term.cur_attr&0x8FFF) | (ansi_col[(n-40)&7]<<12);
1666 		    break;
1667 		}
1668 	    }
1669 	    break;
1670 
1671 	case 'x':
1672 	    if (scp->term.num_param == 0)
1673 		n = 0;
1674 	    else
1675 		n = scp->term.param[0];
1676 	    switch (n) {
1677 	    case 0:     /* reset attributes */
1678 		scp->term.cur_attr = scp->term.std_attr =
1679 		    current_default->std_attr;
1680 		scp->term.rev_attr = current_default->rev_attr;
1681 		break;
1682 	    case 1:     /* set ansi background */
1683 		scp->term.cur_attr = scp->term.std_attr =
1684 		    (scp->term.std_attr & 0x0F00) |
1685 		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
1686 		break;
1687 	    case 2:     /* set ansi foreground */
1688 		scp->term.cur_attr = scp->term.std_attr =
1689 		    (scp->term.std_attr & 0xF000) |
1690 		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
1691 		break;
1692 	    case 3:     /* set ansi attribute directly */
1693 		scp->term.cur_attr = scp->term.std_attr =
1694 		    (scp->term.param[1]&0xFF)<<8;
1695 		break;
1696 	    case 5:     /* set ansi reverse video background */
1697 		scp->term.rev_attr =
1698 		    (scp->term.rev_attr & 0x0F00) |
1699 		    (ansi_col[(scp->term.param[1])&0x0F]<<12);
1700 		break;
1701 	    case 6:     /* set ansi reverse video foreground */
1702 		scp->term.rev_attr =
1703 		    (scp->term.rev_attr & 0xF000) |
1704 		    (ansi_col[(scp->term.param[1])&0x0F]<<8);
1705 		break;
1706 	    case 7:     /* set ansi reverse video directly */
1707 		scp->term.rev_attr =
1708 		    (scp->term.param[1]&0xFF)<<8;
1709 		break;
1710 	    }
1711 	    break;
1712 
1713 	case 'z':   /* switch to (virtual) console n */
1714 	    if (scp->term.num_param == 1)
1715 		switch_scr(scp, scp->term.param[0]);
1716 	    break;
1717 	}
1718     }
1719     else if (scp->term.esc == 3) {
1720 	if (c >= '0' && c <= '9') {
1721 	    if (scp->term.num_param < MAX_ESC_PAR) {
1722 	    if (scp->term.last_param != scp->term.num_param) {
1723 		scp->term.last_param = scp->term.num_param;
1724 		scp->term.param[scp->term.num_param] = 0;
1725 	    }
1726 	    else
1727 		scp->term.param[scp->term.num_param] *= 10;
1728 	    scp->term.param[scp->term.num_param] += c - '0';
1729 	    return;
1730 	    }
1731 	}
1732 	scp->term.num_param = scp->term.last_param + 1;
1733 	switch (c) {
1734 
1735 	case ';':
1736 	    if (scp->term.num_param < MAX_ESC_PAR)
1737 		return;
1738 	    break;
1739 
1740 	case 'A':   /* set display border color */
1741 	    if (scp->term.num_param == 1)
1742 		scp->border=scp->term.param[0] & 0xff;
1743 		if (scp == cur_console)
1744 		    set_border(scp->border);
1745 	    break;
1746 
1747 	case 'B':   /* set bell pitch and duration */
1748 	    if (scp->term.num_param == 2) {
1749 		scp->bell_pitch = scp->term.param[0];
1750 		scp->bell_duration = scp->term.param[1]*10;
1751 	    }
1752 	    break;
1753 
1754 	case 'C':   /* set cursor type & shape */
1755 	    if (scp->term.num_param == 1) {
1756 		if (scp->term.param[0] & 0x01)
1757 		    configuration |= BLINK_CURSOR;
1758 		else
1759 		    configuration &= ~BLINK_CURSOR;
1760 		if (scp->term.param[0] & 0x02) {
1761 		    configuration |= CHAR_CURSOR;
1762 		    set_destructive_cursor(scp, TRUE);
1763 		} else
1764 		    configuration &= ~CHAR_CURSOR;
1765 	    }
1766 	    else if (scp->term.num_param == 2) {
1767 		scp->cursor_start = scp->term.param[0] & 0x1F;
1768 		scp->cursor_end = scp->term.param[1] & 0x1F;
1769 		if (configuration & CHAR_CURSOR)
1770 			set_destructive_cursor(scp, TRUE);
1771 	    }
1772 	    break;
1773 
1774 	case 'F':   /* set ansi foreground */
1775 	    if (scp->term.num_param == 1)
1776 		scp->term.cur_attr = scp->term.std_attr =
1777 		    (scp->term.std_attr & 0xF000)
1778 		    | ((scp->term.param[0] & 0x0F) << 8);
1779 	    break;
1780 
1781 	case 'G':   /* set ansi background */
1782 	    if (scp->term.num_param == 1)
1783 		scp->term.cur_attr = scp->term.std_attr =
1784 		    (scp->term.std_attr & 0x0F00)
1785 		    | ((scp->term.param[0] & 0x0F) << 12);
1786 	    break;
1787 
1788 	case 'H':   /* set ansi reverse video foreground */
1789 	    if (scp->term.num_param == 1)
1790 		scp->term.rev_attr =
1791 		    (scp->term.rev_attr & 0xF000)
1792 		    | ((scp->term.param[0] & 0x0F) << 8);
1793 	    break;
1794 
1795 	case 'I':   /* set ansi reverse video background */
1796 	    if (scp->term.num_param == 1)
1797 		scp->term.rev_attr =
1798 		    (scp->term.rev_attr & 0x0F00)
1799 		    | ((scp->term.param[0] & 0x0F) << 12);
1800 	    break;
1801 	}
1802     }
1803     scp->term.esc = 0;
1804 }
1805 
1806 static inline void
1807 draw_cursor(scr_stat *scp, int show)
1808 {
1809     if (show && !(scp->status & CURSOR_SHOWN)) {
1810 	u_short cursor_image = *(Crtat + (scp->cursor_pos - scp->scr_buf));
1811 
1812 	scp->cursor_saveunder = cursor_image;
1813 	if (configuration & CHAR_CURSOR) {
1814 	    set_destructive_cursor(scp, FALSE);
1815 	    cursor_image = (cursor_image & 0xff00) | DEAD_CHAR;
1816 	}
1817 	else {
1818 	    if ((cursor_image & 0x7000) == 0x7000) {
1819 		cursor_image &= 0x8fff;
1820 		if(!(cursor_image & 0x0700))
1821 		    cursor_image |= 0x0700;
1822 	    } else {
1823 		cursor_image |= 0x7000;
1824 		if ((cursor_image & 0x0700) == 0x0700)
1825 		    cursor_image &= 0xf0ff;
1826 	    }
1827 	}
1828 	*(Crtat + (scp->cursor_pos - scp->scr_buf)) = cursor_image;
1829 	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1830 	scp->status |= CURSOR_SHOWN;
1831     }
1832     if (!show && (scp->status & CURSOR_SHOWN)) {
1833 	*(Crtat + (scp->cursor_pos - scp->scr_buf)) = scp->cursor_saveunder;
1834 	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1835 	scp->status &= ~CURSOR_SHOWN;
1836     }
1837 }
1838 
1839 static void
1840 ansi_put(scr_stat *scp, u_char *buf, int len)
1841 {
1842     u_char *ptr = buf;
1843 
1844     if (scp->status & UNKNOWN_MODE)
1845 	return;
1846 
1847     /* make screensaver happy */
1848     if (scp == cur_console) {
1849 	scrn_time_stamp = time.tv_sec;
1850 	if (scrn_blanked) {
1851 	    (*current_saver)(FALSE);
1852 	    cur_console->start = 0;
1853 	    cur_console->end = cur_console->xsize * cur_console->ysize;
1854 	}
1855     }
1856     write_in_progress++;
1857 outloop:
1858     if (scp->term.esc) {
1859 	scan_esc(scp, *ptr++);
1860 	len--;
1861     }
1862     else if (PRINTABLE(*ptr)) {     /* Print only printables */
1863  	int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
1864  	u_short cur_attr = scp->term.cur_attr;
1865  	u_short *cursor_pos = scp->cursor_pos;
1866 	do {
1867 	    *cursor_pos++ = (scr_map[*ptr++] | cur_attr);
1868 	    cnt--;
1869 	} while (cnt && PRINTABLE(*ptr));
1870 	len -= (cursor_pos - scp->cursor_pos);
1871 	scp->xpos += (cursor_pos - scp->cursor_pos);
1872 	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1873 	mark_for_update(scp, cursor_pos - scp->scr_buf);
1874 	scp->cursor_pos = cursor_pos;
1875 	if (scp->xpos >= scp->xsize) {
1876 	    scp->xpos = 0;
1877 	    scp->ypos++;
1878 	}
1879     }
1880     else  {
1881 	switch(*ptr) {
1882 	case 0x07:
1883 	    do_bell(scp, scp->bell_pitch, scp->bell_duration);
1884 	    break;
1885 
1886 	case 0x08:      /* non-destructive backspace */
1887 	    if (scp->cursor_pos > scp->scr_buf) {
1888 	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1889 		scp->cursor_pos--;
1890 	    	mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1891 		if (scp->xpos > 0)
1892 		    scp->xpos--;
1893 		else {
1894 		    scp->xpos += scp->xsize - 1;
1895 		    scp->ypos--;
1896 		}
1897 	    }
1898 	    break;
1899 
1900 	case 0x09:  /* non-destructive tab */
1901 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1902 	    scp->cursor_pos += (8 - scp->xpos % 8u);
1903 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1904 	    if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
1905 	        scp->xpos = 0;
1906 	        scp->ypos++;
1907 	    }
1908 	    break;
1909 
1910 	case 0x0a:  /* newline, same pos */
1911 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1912 	    scp->cursor_pos += scp->xsize;
1913 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1914 	    scp->ypos++;
1915 	    break;
1916 
1917 	case 0x0c:  /* form feed, clears screen */
1918 	    clear_screen(scp);
1919 	    break;
1920 
1921 	case 0x0d:  /* return, return to pos 0 */
1922 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1923 	    scp->cursor_pos -= scp->xpos;
1924 	    mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1925 	    scp->xpos = 0;
1926 	    break;
1927 
1928 	case 0x1b:  /* start escape sequence */
1929 	    scp->term.esc = 1;
1930 	    scp->term.num_param = 0;
1931 	    break;
1932 	}
1933 	ptr++; len--;
1934     }
1935     /* do we have to scroll ?? */
1936     if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
1937 	if (scp->history) {
1938 	    bcopyw(scp->scr_buf, scp->history_head,
1939 		   scp->xsize * sizeof(u_short));
1940 	    scp->history_head += scp->xsize;
1941 	    if (scp->history_head + scp->xsize >
1942 		scp->history + scp->history_size)
1943 		scp->history_head = scp->history;
1944 	}
1945 	bcopyw(scp->scr_buf + scp->xsize, scp->scr_buf,
1946 	       scp->xsize * (scp->ysize - 1) * sizeof(u_short));
1947 	fillw(scp->term.cur_attr | scr_map[0x20],
1948 	      scp->scr_buf + scp->xsize * (scp->ysize - 1),
1949 	      scp->xsize);
1950 	scp->cursor_pos -= scp->xsize;
1951 	scp->ypos--;
1952     	mark_all(scp);
1953     }
1954     if (len)
1955 	goto outloop;
1956     write_in_progress--;
1957     if (delayed_next_scr)
1958 	switch_scr(scp, delayed_next_scr - 1);
1959 }
1960 
1961 static void
1962 scinit(void)
1963 {
1964     u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
1965     unsigned hw_cursor;
1966     int i;
1967 
1968     if (init_done)
1969 	return;
1970     init_done = TRUE;
1971     /*
1972      * Crtat initialized to point to MONO buffer, if not present change
1973      * to CGA_BUF offset. ONLY add the difference since locore.s adds
1974      * in the remapped offset at the "right" time
1975      */
1976     was = *cp;
1977     *cp = (u_short) 0xA55A;
1978     if (*cp != 0xA55A)
1979 	crtc_addr = MONO_BASE;
1980     else {
1981 	*cp = was;
1982 	crtc_addr = COLOR_BASE;
1983 	Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
1984     }
1985 
1986     /* extract cursor location */
1987     outb(crtc_addr, 14);
1988     hw_cursor = inb(crtc_addr + 1) << 8;
1989     outb(crtc_addr, 15);
1990     hw_cursor |= inb(crtc_addr + 1);
1991 
1992     /* move hardware cursor out of the way */
1993     outb(crtc_addr, 14);
1994     outb(crtc_addr + 1, 0xff);
1995     outb(crtc_addr, 15);
1996     outb(crtc_addr + 1, 0xff);
1997 
1998     /* is this a VGA or higher ? */
1999     outb(crtc_addr, 7);
2000     if (inb(crtc_addr) == 7) {
2001 	u_long  pa;
2002 	u_long  segoff;
2003 
2004 	crtc_vga = TRUE;
2005 	/*
2006 	 * Get the BIOS video mode pointer.
2007 	 */
2008 	segoff = *(u_long *)pa_to_va(0x4a8);
2009 	pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2010 	if (ISMAPPED(pa, sizeof(u_long))) {
2011 	    segoff = *(u_long *)pa_to_va(pa);
2012 	    pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2013 	    if (ISMAPPED(pa, 64))
2014 		video_mode_ptr = (char *)pa_to_va(pa);
2015 	}
2016     }
2017     current_default = &user_default;
2018     console[0] = &main_console;
2019     init_scp(console[0]);
2020     console[0]->scr_buf = console[0]->mouse_pos =  Crtat;
2021     console[0]->cursor_pos = Crtat + hw_cursor;
2022     console[0]->xpos = hw_cursor % COL;
2023     console[0]->ypos = hw_cursor / COL;
2024     cur_console = console[0];
2025     for (i=1; i<MAXCONS; i++)
2026 	console[i] = NULL;
2027     kernel_console.esc = 0;
2028     kernel_console.std_attr = kernel_default.std_attr;
2029     kernel_console.rev_attr = kernel_default.rev_attr;
2030     kernel_console.cur_attr = kernel_default.std_attr;
2031     /* initialize mapscrn array to a one to one map */
2032     for (i=0; i<sizeof(scr_map); i++)
2033 	scr_map[i] = i;
2034 }
2035 
2036 static scr_stat
2037 *alloc_scp()
2038 {
2039     scr_stat *scp;
2040 
2041     scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_NOWAIT);
2042     init_scp(scp);
2043     scp->scr_buf = scp->cursor_pos = scp->scr_buf = scp->mouse_pos =
2044 	(u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
2045 			  M_DEVBUF, M_NOWAIT);
2046     scp->history_head = scp->history_pos = scp->history =
2047 	(u_short *)malloc(scp->history_size*sizeof(u_short),
2048 			  M_DEVBUF, M_NOWAIT);
2049     bzero(scp->history_head, scp->history_size*sizeof(u_short));
2050     if (crtc_vga && video_mode_ptr)
2051 	set_mode(scp);
2052     clear_screen(scp);
2053     return scp;
2054 }
2055 
2056 static void
2057 init_scp(scr_stat *scp)
2058 {
2059     scp->mode = M_VGA_C80x25;
2060     scp->font = FONT_16;
2061     scp->xsize = COL;
2062     scp->ysize = ROW;
2063     scp->start = COL * ROW;
2064     scp->end = 0;
2065     scp->term.esc = 0;
2066     scp->term.std_attr = current_default->std_attr;
2067     scp->term.rev_attr = current_default->rev_attr;
2068     scp->term.cur_attr = scp->term.std_attr;
2069     scp->border = BG_BLACK;
2070     scp->cursor_start = *(char *)pa_to_va(0x461);
2071     scp->cursor_end = *(char *)pa_to_va(0x460);
2072     scp->mouse_xpos = scp->mouse_ypos = 0;
2073     scp->bell_pitch = BELL_PITCH;
2074     scp->bell_duration = BELL_DURATION;
2075     scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
2076     scp->status |= CURSOR_ENABLED;
2077     scp->pid = 0;
2078     scp->proc = NULL;
2079     scp->smode.mode = VT_AUTO;
2080     scp->history_head = scp->history_pos = scp->history = NULL;
2081     scp->history_size = HISTORY_SIZE;
2082 }
2083 
2084 static u_char
2085 *get_fstr(u_int c, u_int *len)
2086 {
2087     u_int i;
2088 
2089     if (!(c & FKEY))
2090 	return(NULL);
2091     i = (c & 0xFF) - F_FN;
2092     if (i > n_fkey_tab)
2093 	return(NULL);
2094     *len = fkey_tab[i].len;
2095     return(fkey_tab[i].str);
2096 }
2097 
2098 static void
2099 update_leds(int which)
2100 {
2101     int s;
2102     static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2103 
2104     /* replace CAPS led with ALTGR led for ALTGR keyboards */
2105     if (key_map.n_keys > ALTGR_OFFSET) {
2106 	if (which & ALKED)
2107 	    which |= CLKED;
2108 	else
2109 	    which &= ~CLKED;
2110     }
2111     s = spltty();
2112     kbd_cmd(KB_SETLEDS);
2113     kbd_cmd(xlate_leds[which & LED_MASK]);
2114     splx(s);
2115 }
2116 
2117 static void
2118 history_to_screen(scr_stat *scp)
2119 {
2120     int i;
2121 
2122     for (i=0; i<scp->ysize; i++)
2123 	bcopyw(scp->history + (((scp->history_pos - scp->history) +
2124 	       scp->history_size-((i+1)*scp->xsize))%scp->history_size),
2125 	       scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
2126 	       scp->xsize * sizeof(u_short));
2127     mark_all(scp);
2128 }
2129 
2130 static int
2131 history_up_line(scr_stat *scp)
2132 {
2133     if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
2134 	scp->history_head) {
2135 	scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
2136 	history_to_screen(scp);
2137 	return 0;
2138     }
2139     else
2140 	return -1;
2141 }
2142 
2143 static int
2144 history_down_line(scr_stat *scp)
2145 {
2146     if (scp->history_pos != scp->history_head) {
2147 	scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
2148 	history_to_screen(scp);
2149 	return 0;
2150     }
2151     else
2152 	return -1;
2153 }
2154 
2155 /*
2156  * scgetc(noblock) - get character from keyboard.
2157  * If noblock = 0 wait until a key is pressed.
2158  * Else return NOKEY.
2159  */
2160 u_int
2161 scgetc(int noblock)
2162 {
2163     u_char scancode, keycode;
2164     u_int state, action;
2165     struct key_t *key;
2166     static u_char esc_flag = 0, compose = 0;
2167     static u_int chr = 0;
2168 
2169 next_code:
2170     kbd_wait();
2171     /* First see if there is something in the keyboard port */
2172     if (inb(KB_STAT) & KB_BUF_FULL)
2173 	scancode = inb(KB_DATA);
2174     else if (noblock)
2175 	return(NOKEY);
2176     else
2177 	goto next_code;
2178 
2179     if (cur_console->status & KBD_RAW_MODE)
2180 	return scancode;
2181 #if ASYNCH
2182     if (scancode == KB_ACK || scancode == KB_RESEND) {
2183 	kbd_reply = scancode;
2184 	if (noblock)
2185 	    return(NOKEY);
2186 	goto next_code;
2187     }
2188 #endif
2189     keycode = scancode & 0x7F;
2190     switch (esc_flag) {
2191     case 0x00:      /* normal scancode */
2192 	switch(scancode) {
2193 	case 0xB8:  /* left alt  (compose key) */
2194 	    if (compose) {
2195 		compose = 0;
2196 		if (chr > 255) {
2197 		    do_bell(cur_console,
2198 			BELL_PITCH, BELL_DURATION);
2199 		    chr = 0;
2200 		}
2201 	    }
2202 	    break;
2203 	case 0x38:
2204 	    if (!compose) {
2205 		compose = 1;
2206 		chr = 0;
2207 	    }
2208 	    break;
2209 	case 0xE0:
2210 	case 0xE1:
2211 	    esc_flag = scancode;
2212 	    goto next_code;
2213 	}
2214 	break;
2215     case 0xE0:      /* 0xE0 prefix */
2216 	esc_flag = 0;
2217 	switch (keycode) {
2218 	case 0x1C:  /* right enter key */
2219 	    keycode = 0x59;
2220 	    break;
2221 	case 0x1D:  /* right ctrl key */
2222 	    keycode = 0x5A;
2223 	    break;
2224 	case 0x35:  /* keypad divide key */
2225 	    keycode = 0x5B;
2226 	    break;
2227 	case 0x37:  /* print scrn key */
2228 	    keycode = 0x5C;
2229 	    break;
2230 	case 0x38:  /* right alt key (alt gr) */
2231 	    keycode = 0x5D;
2232 	    break;
2233 	case 0x47:  /* grey home key */
2234 	    keycode = 0x5E;
2235 	    break;
2236 	case 0x48:  /* grey up arrow key */
2237 	    keycode = 0x5F;
2238 	    break;
2239 	case 0x49:  /* grey page up key */
2240 	    keycode = 0x60;
2241 	    break;
2242 	case 0x4B:  /* grey left arrow key */
2243 	    keycode = 0x61;
2244 	    break;
2245 	case 0x4D:  /* grey right arrow key */
2246 	    keycode = 0x62;
2247 	    break;
2248 	case 0x4F:  /* grey end key */
2249 	    keycode = 0x63;
2250 	    break;
2251 	case 0x50:  /* grey down arrow key */
2252 	    keycode = 0x64;
2253 	    break;
2254 	case 0x51:  /* grey page down key */
2255 	    keycode = 0x65;
2256 	    break;
2257 	case 0x52:  /* grey insert key */
2258 	    keycode = 0x66;
2259 	    break;
2260 	case 0x53:  /* grey delete key */
2261 	    keycode = 0x67;
2262 	    break;
2263 
2264 	/* the following 3 are only used on the MS "Natural" keyboard */
2265 	case 0x5b:  /* left Window key */
2266 	    keycode = 0x69;
2267 	    break;
2268 	case 0x5c:  /* right Window key */
2269 	    keycode = 0x6a;
2270 	    break;
2271 	case 0x5d:  /* menu key */
2272 	    keycode = 0x6b;
2273 	    break;
2274 	default:    /* ignore everything else */
2275 	    goto next_code;
2276 	}
2277 	break;
2278     case 0xE1:      /* 0xE1 prefix */
2279 	esc_flag = 0;
2280 	if (keycode == 0x1D)
2281 	    esc_flag = 0x1D;
2282 	goto next_code;
2283 	/* NOT REACHED */
2284     case 0x1D:      /* pause / break */
2285 	esc_flag = 0;
2286 	if (keycode != 0x45)
2287 	    goto next_code;
2288 	keycode = 0x68;
2289 	break;
2290     }
2291 
2292     /* if scroll-lock pressed allow history browsing */
2293     if (cur_console->history && cur_console->status & SLKED) {
2294 	int i;
2295 
2296 	cur_console->status &= ~CURSOR_ENABLED;
2297 	if (!(cur_console->status & BUFFER_SAVED)) {
2298 	    cur_console->status |= BUFFER_SAVED;
2299 	    cur_console->history_save = cur_console->history_head;
2300 
2301 	    /* copy screen into top of history buffer */
2302 	    for (i=0; i<cur_console->ysize; i++) {
2303 		bcopyw(cur_console->scr_buf + (cur_console->xsize * i),
2304 		       cur_console->history_head,
2305 		       cur_console->xsize * sizeof(u_short));
2306 		cur_console->history_head += cur_console->xsize;
2307 		if (cur_console->history_head + cur_console->xsize >
2308 		    cur_console->history + cur_console->history_size)
2309 		    cur_console->history_head=cur_console->history;
2310 	    }
2311 	    cur_console->history_pos = cur_console->history_head;
2312 	    history_to_screen(cur_console);
2313 	}
2314 	switch (scancode) {
2315 	case 0x47:  /* home key */
2316 	    cur_console->history_pos = cur_console->history_head;
2317 	    history_to_screen(cur_console);
2318 	    goto next_code;
2319 
2320 	case 0x4F:  /* end key */
2321 	    cur_console->history_pos =
2322 		WRAPHIST(cur_console, cur_console->history_head,
2323 			 cur_console->xsize*cur_console->ysize);
2324 	    history_to_screen(cur_console);
2325 	    goto next_code;
2326 
2327 	case 0x48:  /* up arrow key */
2328 	    if (history_up_line(cur_console))
2329 		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2330 	    goto next_code;
2331 
2332 	case 0x50:  /* down arrow key */
2333 	    if (history_down_line(cur_console))
2334 		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2335 	    goto next_code;
2336 
2337 	case 0x49:  /* page up key */
2338 	    for (i=0; i<cur_console->ysize; i++)
2339 	    if (history_up_line(cur_console)) {
2340 		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2341 		break;
2342 	    }
2343 	    goto next_code;
2344 
2345 	case 0x51:  /* page down key */
2346 	    for (i=0; i<cur_console->ysize; i++)
2347 	    if (history_down_line(cur_console)) {
2348 		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2349 		break;
2350 	    }
2351 	    goto next_code;
2352 	}
2353     }
2354 
2355     if (compose) {
2356 	switch (scancode) {
2357 	/* key pressed process it */
2358 	case 0x47: case 0x48: case 0x49:    /* keypad 7,8,9 */
2359 	    chr = (scancode - 0x40) + chr*10;
2360 	    goto next_code;
2361 	case 0x4B: case 0x4C: case 0x4D:    /* keypad 4,5,6 */
2362 	    chr = (scancode - 0x47) + chr*10;
2363 	    goto next_code;
2364 	case 0x4F: case 0x50: case 0x51:    /* keypad 1,2,3 */
2365 	    chr = (scancode - 0x4E) + chr*10;
2366 	    goto next_code;
2367 	case 0x52:              /* keypad 0 */
2368 	    chr *= 10;
2369 	    goto next_code;
2370 
2371 	/* key release, no interest here */
2372 	case 0xC7: case 0xC8: case 0xC9:    /* keypad 7,8,9 */
2373 	case 0xCB: case 0xCC: case 0xCD:    /* keypad 4,5,6 */
2374 	case 0xCF: case 0xD0: case 0xD1:    /* keypad 1,2,3 */
2375 	case 0xD2:              /* keypad 0 */
2376 	    goto next_code;
2377 
2378 	case 0x38:              /* left alt key */
2379 	    break;
2380 	default:
2381 	    if (chr) {
2382 		compose = chr = 0;
2383 		do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2384 		goto next_code;
2385 	    }
2386 	    break;
2387 	}
2388     }
2389 
2390     state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
2391     if ((!agrs && (cur_console->status & ALKED))
2392 	|| (agrs && !(cur_console->status & ALKED)))
2393 	keycode += ALTGR_OFFSET;
2394     key = &key_map.key[keycode];
2395     if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
2396 	 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
2397 	state ^= 1;
2398 
2399     /* Check for make/break */
2400     action = key->map[state];
2401     if (scancode & 0x80) {      /* key released */
2402 	if (key->spcl & 0x80) {
2403 	    switch (action) {
2404 	    case LSH:
2405 		shfts &= ~1;
2406 		break;
2407 	    case RSH:
2408 		shfts &= ~2;
2409 		break;
2410 	    case LCTR:
2411 		ctls &= ~1;
2412 		break;
2413 	    case RCTR:
2414 		ctls &= ~2;
2415 		break;
2416 	    case LALT:
2417 		alts &= ~1;
2418 		break;
2419 	    case RALT:
2420 		alts &= ~2;
2421 		break;
2422 	    case NLK:
2423 		nlkcnt = 0;
2424 		break;
2425 	    case CLK:
2426 		clkcnt = 0;
2427 		break;
2428 	    case SLK:
2429 		slkcnt = 0;
2430 		break;
2431 	    case ASH:
2432 		agrs = 0;
2433 		break;
2434 	    case ALK:
2435 		alkcnt = 0;
2436 		break;
2437 	    case META:
2438 		metas = 0;
2439 		break;
2440 	    }
2441 	}
2442 	if (chr && !compose) {
2443 	    action = chr;
2444 	    chr = 0;
2445 	    return(action);
2446 	}
2447     } else {
2448 	/* key pressed */
2449 	if (key->spcl & (0x80>>state)) {
2450 	    switch (action) {
2451 	    /* LOCKING KEYS */
2452 	    case NLK:
2453 		if (!nlkcnt) {
2454 		    nlkcnt++;
2455 		    if (cur_console->status & NLKED)
2456 			cur_console->status &= ~NLKED;
2457 		    else
2458 			cur_console->status |= NLKED;
2459 		    update_leds(cur_console->status);
2460 		}
2461 		break;
2462 	    case CLK:
2463 		if (!clkcnt) {
2464 		    clkcnt++;
2465 		    if (cur_console->status & CLKED)
2466 			cur_console->status &= ~CLKED;
2467 		    else
2468 			cur_console->status |= CLKED;
2469 		    update_leds(cur_console->status);
2470 		}
2471 		break;
2472 	    case SLK:
2473 		if (!slkcnt) {
2474 		    slkcnt++;
2475 		    if (cur_console->status & SLKED) {
2476 			cur_console->status &= ~SLKED;
2477 			if (cur_console->status & BUFFER_SAVED){
2478 			    int i;
2479 			    u_short *ptr = cur_console->history_save;
2480 
2481 			    for (i=0; i<cur_console->ysize; i++) {
2482 				bcopyw(ptr,
2483 				       cur_console->scr_buf +
2484 				       (cur_console->xsize*i),
2485 				       cur_console->xsize * sizeof(u_short));
2486 				ptr += cur_console->xsize;
2487 				if (ptr + cur_console->xsize >
2488 				    cur_console->history +
2489 				    cur_console->history_size)
2490 				    ptr = cur_console->history;
2491 			    }
2492 			    cur_console->status &= ~BUFFER_SAVED;
2493 			    cur_console->history_head=cur_console->history_save;
2494 			    cur_console->status |= CURSOR_ENABLED;
2495 			    mark_all(cur_console);
2496 			}
2497 			scstart(VIRTUAL_TTY(get_scr_num()));
2498 		    }
2499 		    else
2500 			cur_console->status |= SLKED;
2501 		    update_leds(cur_console->status);
2502 		}
2503 		break;
2504 	    case ALK:
2505 		if (!alkcnt) {
2506 		    alkcnt++;
2507 		    if (cur_console->status & ALKED)
2508 			cur_console->status &= ~ALKED;
2509 		    else
2510 			cur_console->status |= ALKED;
2511 		    update_leds(cur_console->status);
2512 		}
2513 		break;
2514 
2515 	    /* NON-LOCKING KEYS */
2516 	    case NOP:
2517 		break;
2518 	    case RBT:
2519 		shutdown_nice();
2520 		break;
2521 	    case SUSP:
2522 #if NAPM > 0
2523 		apm_suspend();
2524 #endif
2525 		break;
2526 
2527 	    case DBG:
2528 #ifdef DDB          /* try to switch to console 0 */
2529 		if (cur_console->smode.mode == VT_AUTO &&
2530 		    console[0]->smode.mode == VT_AUTO)
2531 		    switch_scr(cur_console, 0);
2532 		Debugger("manual escape to debugger");
2533 		return(NOKEY);
2534 #else
2535 		printf("No debugger in kernel\n");
2536 #endif
2537 		break;
2538 	    case LSH:
2539 		shfts |= 1;
2540 		break;
2541 	    case RSH:
2542 		shfts |= 2;
2543 		break;
2544 	    case LCTR:
2545 		ctls |= 1;
2546 		break;
2547 	    case RCTR:
2548 		ctls |= 2;
2549 		break;
2550 	    case LALT:
2551 		alts |= 1;
2552 		break;
2553 	    case RALT:
2554 		alts |= 2;
2555 		break;
2556 	    case ASH:
2557 		agrs = 1;
2558 		break;
2559 	    case META:
2560 		metas = 1;
2561 		break;
2562 	    case NEXT:
2563 		switch_scr(cur_console, (get_scr_num() + 1) % MAXCONS);
2564 		break;
2565 	    case BTAB:
2566 		return(BKEY);
2567 	    default:
2568 		if (action >= F_SCR && action <= L_SCR) {
2569 		    switch_scr(cur_console, action - F_SCR);
2570 		    break;
2571 		}
2572 		if (action >= F_FN && action <= L_FN)
2573 		    action |= FKEY;
2574 		return(action);
2575 	    }
2576 	}
2577 	else {
2578 	    if (metas)
2579 		action |= MKEY;
2580 	    return(action);
2581 	}
2582     }
2583     goto next_code;
2584 }
2585 
2586 int
2587 scmmap(dev_t dev, int offset, int nprot)
2588 {
2589     if (offset > 0x20000 - PAGE_SIZE)
2590 	return -1;
2591     return i386_btop((VIDEOMEM + offset));
2592 }
2593 
2594 static void
2595 kbd_wait(void)
2596 {
2597     int i = 1000;
2598 
2599     while (i--) {
2600 	if ((inb(KB_STAT) & KB_READY) == 0)
2601 	    break;
2602 	DELAY (10);
2603     }
2604 }
2605 
2606 static void
2607 kbd_cmd(u_char command)
2608 {
2609     int retry = 5;
2610     do {
2611 	int i = 100000;
2612 
2613 	kbd_wait();
2614 #if ASYNCH
2615 	kbd_reply = 0;
2616 	outb(KB_DATA, command);
2617 	while (i--) {
2618 	    if (kbd_reply == KB_ACK)
2619 		return;
2620 	    if (kbd_reply == KB_RESEND)
2621 		break;
2622 	}
2623 #else
2624 	outb(KB_DATA, command);
2625 	while (i--) {
2626 	    if (inb(KB_STAT) & KB_BUF_FULL) {
2627 		int val;
2628 		DELAY(10);
2629 		val = inb(KB_DATA);
2630 		if (val == KB_ACK)
2631 		    return;
2632 		if (val == KB_RESEND)
2633 		    break;
2634 	    }
2635 	}
2636 #endif
2637     } while (retry--);
2638 }
2639 
2640 static void
2641 set_mode(scr_stat *scp)
2642 {
2643     char *modetable;
2644     char special_modetable[64];
2645     int mode, font_size;
2646 
2647     if (scp != cur_console)
2648 	return;
2649 
2650     /* setup video hardware for the given mode */
2651     switch (scp->mode) {
2652     case M_VGA_M80x60:
2653 	bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2654 	goto special_80x60;
2655 
2656     case M_VGA_C80x60:
2657 	bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2658 special_80x60:
2659 	special_modetable[2]  = 0x08;
2660 	special_modetable[19] = 0x47;
2661 	goto special_480l;
2662 
2663     case M_VGA_M80x30:
2664 	bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2665 	goto special_80x30;
2666 
2667     case M_VGA_C80x30:
2668 	bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2669 special_80x30:
2670 	special_modetable[19] = 0x4f;
2671 special_480l:
2672 	special_modetable[9] |= 0xc0;
2673 	special_modetable[16] = 0x08;
2674 	special_modetable[17] = 0x3e;
2675 	special_modetable[26] = 0xea;
2676 	special_modetable[28] = 0xdf;
2677 	special_modetable[31] = 0xe7;
2678 	special_modetable[32] = 0x04;
2679 	modetable = special_modetable;
2680 	goto setup_mode;
2681 
2682     case M_ENH_B80x43:
2683 	bcopyw(video_mode_ptr+(64*M_ENH_B80x25),&special_modetable, 64);
2684 	goto special_80x43;
2685 
2686     case M_ENH_C80x43:
2687 	bcopyw(video_mode_ptr+(64*M_ENH_C80x25),&special_modetable, 64);
2688 special_80x43:
2689 	special_modetable[28] = 87;
2690 	goto special_80x50;
2691 
2692     case M_VGA_M80x50:
2693 	bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2694 	goto special_80x50;
2695 
2696     case M_VGA_C80x50:
2697 	bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2698 special_80x50:
2699 	special_modetable[2] = 8;
2700 	special_modetable[19] = 7;
2701 	modetable = special_modetable;
2702 	goto setup_mode;
2703 
2704     case M_VGA_C40x25: case M_VGA_C80x25:
2705     case M_VGA_M80x25:
2706     case M_B40x25:     case M_C40x25:
2707     case M_B80x25:     case M_C80x25:
2708     case M_ENH_B40x25: case M_ENH_C40x25:
2709     case M_ENH_B80x25: case M_ENH_C80x25:
2710 
2711 	modetable = video_mode_ptr + (scp->mode * 64);
2712 setup_mode:
2713 	set_vgaregs(modetable);
2714 	font_size = *(modetable + 2);
2715 
2716 	/* set font type (size) */
2717 	switch (font_size) {
2718 	case 0x10:
2719 	    outb(TSIDX, 0x03); outb(TSREG, 0x00);   /* font 0 */
2720 	    scp->font = FONT_16;
2721 	    break;
2722 	case 0x0E:
2723 	    outb(TSIDX, 0x03); outb(TSREG, 0x05);   /* font 1 */
2724 	    scp->font = FONT_14;
2725 	    break;
2726 	default:
2727 	case 0x08:
2728 	    outb(TSIDX, 0x03); outb(TSREG, 0x0A);   /* font 2 */
2729 	    scp->font = FONT_8;
2730 	    break;
2731 	}
2732 	if (configuration & CHAR_CURSOR)
2733 	    set_destructive_cursor(scp, TRUE);
2734 	break;
2735 
2736     case M_BG320:     case M_CG320:     case M_BG640:
2737     case M_CG320_D:   case M_CG640_E:
2738     case M_CG640x350: case M_ENH_CG640:
2739     case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
2740 
2741 	set_vgaregs(video_mode_ptr + (scp->mode * 64));
2742 	break;
2743 
2744     default:
2745 	/* call user defined function XXX */
2746 	break;
2747     }
2748 
2749     /* set border color for this (virtual) console */
2750     set_border(scp->border);
2751     return;
2752 }
2753 
2754 void
2755 set_border(int color)
2756 {
2757     inb(crtc_addr+6);               /* reset flip-flop */
2758     outb(ATC, 0x11); outb(ATC, color);
2759     inb(crtc_addr+6);               /* reset flip-flop */
2760     outb(ATC, 0x20);                /* enable Palette */
2761 }
2762 
2763 static void
2764 set_vgaregs(char *modetable)
2765 {
2766     int i, s = splhigh();
2767 
2768     outb(TSIDX, 0x00); outb(TSREG, 0x01);   	/* stop sequencer */
2769     outb(TSIDX, 0x07); outb(TSREG, 0x00);   	/* unlock registers */
2770     for (i=0; i<4; i++) {           		/* program sequencer */
2771 	outb(TSIDX, i+1);
2772 	outb(TSREG, modetable[i+5]);
2773     }
2774     outb(MISC, modetable[9]);       		/* set dot-clock */
2775     outb(TSIDX, 0x00); outb(TSREG, 0x03);   	/* start sequencer */
2776     outb(crtc_addr, 0x11);
2777     outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
2778     for (i=0; i<25; i++) {          		/* program crtc */
2779 	outb(crtc_addr, i);
2780 	if (i == 14 || i == 15)     		/* no hardware cursor */
2781 	    outb(crtc_addr+1, 0xff);
2782 	else
2783 	    outb(crtc_addr+1, modetable[i+10]);
2784     }
2785     inb(crtc_addr+6);           		/* reset flip-flop */
2786     for (i=0; i<20; i++) {          		/* program attribute ctrl */
2787 	outb(ATC, i);
2788 	outb(ATC, modetable[i+35]);
2789     }
2790     for (i=0; i<9; i++) {           		/* program graph data ctrl */
2791 	outb(GDCIDX, i);
2792 	outb(GDCREG, modetable[i+55]);
2793     }
2794     inb(crtc_addr+6);           		/* reset flip-flop */
2795     outb(ATC ,0x20);            		/* enable palette */
2796     splx(s);
2797 }
2798 
2799 static void
2800 set_font_mode()
2801 {
2802     /* setup vga for loading fonts (graphics plane mode) */
2803     inb(crtc_addr+6);
2804     outb(ATC, 0x30); outb(ATC, 0x01);
2805 #if SLOW_VGA
2806     outb(TSIDX, 0x02); outb(TSREG, 0x04);
2807     outb(TSIDX, 0x04); outb(TSREG, 0x06);
2808     outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
2809     outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
2810     outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
2811 #else
2812     outw(TSIDX, 0x0402);
2813     outw(TSIDX, 0x0604);
2814     outw(GDCIDX, 0x0204);
2815     outw(GDCIDX, 0x0005);
2816     outw(GDCIDX, 0x0506);               /* addr = a0000, 64kb */
2817 #endif
2818 }
2819 
2820 static void
2821 set_normal_mode()
2822 {
2823     int s = splhigh();
2824 
2825     /* setup vga for normal operation mode again */
2826     inb(crtc_addr+6);
2827     outb(ATC, 0x30); outb(ATC, 0x0C);
2828 #if SLOW_VGA
2829     outb(TSIDX, 0x02); outb(TSREG, 0x03);
2830     outb(TSIDX, 0x04); outb(TSREG, 0x02);
2831     outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
2832     outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
2833     if (crtc_addr == MONO_BASE) {
2834 	outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
2835     }
2836     else {
2837 	outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
2838     }
2839 #else
2840     outw(TSIDX, 0x0302);
2841     outw(TSIDX, 0x0204);
2842     outw(GDCIDX, 0x0004);
2843     outw(GDCIDX, 0x1005);
2844     if (crtc_addr == MONO_BASE)
2845 	outw(GDCIDX, 0x0A06);           /* addr = b0000, 32kb */
2846     else
2847 	outw(GDCIDX, 0x0E06);           /* addr = b8000, 32kb */
2848 #endif
2849     splx(s);
2850 }
2851 
2852 static void
2853 copy_font(int operation, int font_type, char* font_image)
2854 {
2855     int ch, line, segment, fontsize;
2856     u_char val;
2857 
2858     switch (font_type) {
2859     default:
2860     case FONT_8:
2861 	segment = 0x8000;
2862 	fontsize = 8;
2863 	break;
2864     case FONT_14:
2865 	segment = 0x4000;
2866 	fontsize = 14;
2867 	break;
2868     case FONT_16:
2869 	segment = 0x0000;
2870 	fontsize = 16;
2871 	break;
2872     }
2873     outb(TSIDX, 0x01); val = inb(TSREG);        /* disable screen */
2874     outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
2875     set_font_mode();
2876     for (ch=0; ch < 256; ch++)
2877 	for (line=0; line < fontsize; line++)
2878 	if (operation)
2879 	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
2880 		    font_image[(ch*fontsize)+line];
2881 	else
2882 	    font_image[(ch*fontsize)+line] =
2883 	    *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
2884     set_normal_mode();
2885     outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
2886 }
2887 
2888 static void
2889 set_destructive_cursor(scr_stat *scp, int force)
2890 {
2891     u_char cursor[32];
2892     caddr_t address;
2893     int i, font_size;
2894     char *font_buffer;
2895     static u_char old_saveunder = DEAD_CHAR;
2896 
2897     if (!force && (scp->cursor_saveunder & 0xFF) == old_saveunder)
2898 	return;
2899     old_saveunder = force ? DEAD_CHAR : scp->cursor_saveunder & 0xFF;
2900     switch (scp->font) {
2901     default:
2902     case FONT_8:
2903 	font_size = 8;
2904 	font_buffer = font_8;
2905 	address = (caddr_t)VIDEOMEM + 0x8000;
2906 	break;
2907     case FONT_14:
2908 	font_size = 14;
2909 	font_buffer = font_14;
2910 	address = (caddr_t)VIDEOMEM + 0x4000;
2911 	break;
2912     case FONT_16:
2913 	font_size = 16;
2914 	font_buffer = font_16;
2915 	address = (caddr_t)VIDEOMEM;
2916 	break;
2917     }
2918     bcopyw(font_buffer + ((scp->cursor_saveunder & 0xff) * font_size),
2919 	   cursor, font_size);
2920     for (i=0; i<32; i++)
2921 	if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
2922 	    (scp->cursor_start >= font_size && i == font_size - 1))
2923 	    cursor[i] |= 0xff;
2924     while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
2925     set_font_mode();
2926     bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
2927     set_normal_mode();
2928 }
2929 
2930 static void
2931 draw_mouse_image(scr_stat *scp)
2932 {
2933     caddr_t address;
2934     int i, font_size;
2935     char *font_buffer;
2936     u_short buffer[32];
2937     u_short xoffset, yoffset;
2938     u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
2939 
2940     xoffset = scp->mouse_xpos % 8;
2941     switch (scp->font) {
2942     default:
2943     case FONT_8:
2944 	font_size = 8;
2945 	font_buffer = font_8;
2946 	yoffset = scp->mouse_ypos % 8;
2947 	address = (caddr_t)VIDEOMEM + 0x8000;
2948 	break;
2949     case FONT_14:
2950 	font_size = 14;
2951 	font_buffer = font_14;
2952 	yoffset = scp->mouse_ypos % 14;
2953 	address = (caddr_t)VIDEOMEM + 0x4000;
2954 	break;
2955     case FONT_16:
2956 	font_size = 16;
2957 	font_buffer = font_16;
2958 	yoffset = scp->mouse_ypos % 16;
2959 	address = (caddr_t)VIDEOMEM;
2960 	break;
2961     }
2962 
2963     bcopyw(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
2964 	   &scp->mouse_cursor[0], font_size);
2965     bcopyw(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
2966 	   &scp->mouse_cursor[32], font_size);
2967     bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
2968 	   &scp->mouse_cursor[64], font_size);
2969     bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
2970 	   &scp->mouse_cursor[96], font_size);
2971 
2972     for (i=0; i<font_size; i++) {
2973 	buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
2974 	buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
2975     }
2976     for (i=0; i<16; i++) {
2977 	buffer[i+yoffset] =
2978 	    ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
2979 	    | (mouse_or_mask[i] >> xoffset);
2980     }
2981     for (i=0; i<font_size; i++) {
2982 	scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
2983 	scp->mouse_cursor[i+32] = buffer[i] & 0xff;
2984 	scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
2985 	scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
2986     }
2987     if (scp->status & UPDATE_MOUSE) {
2988 	u_short *ptr = scp->scr_buf + (scp->mouse_oldpos - Crtat);
2989 
2990 	if (crt_pos != scp->mouse_oldpos) {
2991 	    *(scp->mouse_oldpos) = scp->mouse_saveunder[0];
2992 	    *(scp->mouse_oldpos+1) = scp->mouse_saveunder[1];
2993 	    *(scp->mouse_oldpos+scp->xsize) = scp->mouse_saveunder[2];
2994 	    *(scp->mouse_oldpos+scp->xsize+1) = scp->mouse_saveunder[3];
2995 	}
2996 	scp->mouse_saveunder[0] = *(scp->mouse_pos);
2997 	scp->mouse_saveunder[1] = *(scp->mouse_pos+1);
2998 	scp->mouse_saveunder[2] = *(scp->mouse_pos+scp->xsize);
2999 	scp->mouse_saveunder[3] = *(scp->mouse_pos+scp->xsize+1);
3000 	if ((scp->cursor_pos == (ptr)) ||
3001 	    (scp->cursor_pos == (ptr+1)) ||
3002 	    (scp->cursor_pos == (ptr+scp->xsize)) ||
3003 	    (scp->cursor_pos == (ptr+scp->xsize+1)) ||
3004 	    (scp->cursor_pos == (scp->mouse_pos)) ||
3005 	    (scp->cursor_pos == (scp->mouse_pos+1)) ||
3006 	    (scp->cursor_pos == (scp->mouse_pos+scp->xsize)) ||
3007 	    (scp->cursor_pos == (scp->mouse_pos+scp->xsize+1)))
3008 	    scp->status &= ~CURSOR_SHOWN;
3009     }
3010     scp->mouse_oldpos = crt_pos;
3011     while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3012     *(crt_pos) = *(scp->mouse_pos)&0xff00|0xd0;
3013     *(crt_pos+1) = *(scp->mouse_pos+1)&0xff00|0xd1;
3014     *(crt_pos+scp->xsize) = *(scp->mouse_pos+scp->xsize)&0xff00|0xd2;
3015     *(crt_pos+scp->xsize+1) = *(scp->mouse_pos+scp->xsize+1)&0xff00|0xd3;
3016     set_font_mode();
3017     bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
3018     set_normal_mode();
3019 }
3020 
3021 static void
3022 save_palette(void)
3023 {
3024     int i;
3025 
3026     outb(PALRADR, 0x00);
3027     for (i=0x00; i<0x300; i++)
3028 	palette[i] = inb(PALDATA);
3029     inb(crtc_addr+6);           /* reset flip/flop */
3030 }
3031 
3032 void
3033 load_palette(void)
3034 {
3035     int i;
3036 
3037     outb(PIXMASK, 0xFF);            /* no pixelmask */
3038     outb(PALWADR, 0x00);
3039     for (i=0x00; i<0x300; i++)
3040 	 outb(PALDATA, palette[i]);
3041     inb(crtc_addr+6);           /* reset flip/flop */
3042     outb(ATC, 0x20);            /* enable palette */
3043 }
3044 
3045 static void
3046 do_bell(scr_stat *scp, int pitch, int duration)
3047 {
3048     if (scp == cur_console) {
3049 	if (configuration & VISUAL_BELL) {
3050 	    if (blink_in_progress)
3051 		return;
3052 	    blink_in_progress = 4;
3053 	    blink_screen(scp);
3054 	    timeout((timeout_func_t)blink_screen, scp, hz/10);
3055 	}
3056 	else
3057 	    sysbeep(pitch, duration);
3058     }
3059 }
3060 
3061 static void
3062 blink_screen(scr_stat *scp)
3063 {
3064     if (blink_in_progress > 1) {
3065 	if (blink_in_progress & 1)
3066 	    fillw(kernel_default.std_attr | scr_map[0x20],
3067 		  Crtat, scp->xsize * scp->ysize);
3068 	else
3069 	    fillw(kernel_default.rev_attr | scr_map[0x20],
3070 		  Crtat, scp->xsize * scp->ysize);
3071 	blink_in_progress--;
3072 	timeout((timeout_func_t)blink_screen, scp, hz/10);
3073     }
3074     else {
3075 	blink_in_progress = FALSE;
3076     	mark_all(scp);
3077 	if (delayed_next_scr)
3078 	    switch_scr(scp, delayed_next_scr - 1);
3079     }
3080 }
3081 
3082 #endif /* NSC */
3083