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