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