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