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