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