syscons.c revision 3671
1/*-
2 * Copyright (c) 1992-1994 S�ren Schmidt
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * William Jolitz and Don Ahn.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer
14 *    in this position and unchanged.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	$Id: syscons.c,v 1.67 1994/10/17 21:16:41 phk Exp $
39 */
40
41#include "sc.h"
42
43#if NSC > 0
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/conf.h>
48#include <sys/ioctl.h>
49#include <sys/proc.h>
50#include <sys/user.h>
51#include <sys/tty.h>
52#include <sys/uio.h>
53#include <sys/callout.h>
54#include <sys/kernel.h>
55#include <sys/syslog.h>
56#include <sys/errno.h>
57#include <sys/malloc.h>
58#include <machine/console.h>
59#include <machine/psl.h>
60#include <machine/frame.h>
61#include <machine/pc/display.h>
62#include <i386/isa/isa.h>
63#include <i386/isa/isa_device.h>
64#include <i386/isa/timerreg.h>
65#include <i386/isa/kbdtables.h>
66#include <i386/i386/cons.h>
67
68#if !defined(NCONS)
69#define NCONS 12
70#endif
71
72#if defined(HARDFONTS)
73#include <i386/isa/iso8859.font>
74#endif
75
76/* status flags */
77#define LOCK_KEY_MASK	0x0000F
78#define LED_MASK	0x00007
79#define UNKNOWN_MODE	0x00010
80#define KBD_RAW_MODE	0x00020
81#define SWITCH_WAIT_REL	0x00040
82#define SWITCH_WAIT_ACQ	0x00080
83
84/* video hardware memory addresses */
85#define VIDEOMEM	0x000A0000
86
87/* misc defines */
88#define MAX_ESC_PAR 	5
89#define	LOAD		1
90#define SAVE		0
91#define	COL		80
92#define	ROW		25
93#define BELL_DURATION	5
94#define BELL_PITCH	800
95#define TIMER_FREQ	1193182			/* should be in isa.h */
96#define CONSOLE_BUFSIZE 1024
97#define PCBURST		128
98#define FONT_8_LOADED	0x001
99#define FONT_14_LOADED	0x002
100#define FONT_16_LOADED	0x004
101
102/* defines related to hardware addresses */
103#define	MONO_BASE	0x3B4			/* crt controller base mono */
104#define	COLOR_BASE	0x3D4			/* crt controller base color */
105#define MISC		0x3C2			/* misc output register */
106#define ATC		IO_VGA+0x00		/* attribute controller */
107#define TSIDX		IO_VGA+0x04		/* timing sequencer idx */
108#define TSREG		IO_VGA+0x05		/* timing sequencer data */
109#define PIXMASK		IO_VGA+0x06		/* pixel write mask */
110#define PALRADR		IO_VGA+0x07		/* palette read address */
111#define PALWADR		IO_VGA+0x08		/* palette write address */
112#define PALDATA		IO_VGA+0x09		/* palette data register */
113#define GDCIDX		IO_VGA+0x0E		/* graph data controller idx */
114#define GDCREG		IO_VGA+0x0F		/* graph data controller data */
115
116/* special characters */
117#define cntlc	0x03
118#define cntld	0x04
119#define bs	0x08
120#define lf	0x0a
121#define cr	0x0d
122#define del	0x7f
123
124typedef struct term_stat {
125	int 		esc;			/* processing escape sequence */
126	int 		num_param;		/* # of parameters to ESC */
127	int	 	last_param;		/* last parameter # */
128	int 		param[MAX_ESC_PAR];	/* contains ESC parameters */
129	int 		cur_attr;		/* current attributes */
130	int 		std_attr;		/* normal attributes */
131	int 		rev_attr;		/* reverse attributes */
132} term_stat;
133
134typedef struct scr_stat {
135	u_short 	*crt_base;		/* address of screen memory */
136	u_short 	*scr_buf;		/* buffer when off screen */
137	u_short 	*crtat;			/* cursor address */
138	int 		xpos;			/* current X position */
139	int 		ypos;			/* current Y position */
140	int 		xsize;			/* X size */
141	int 		ysize;			/* Y size */
142	term_stat 	term;			/* terminal emulation stuff */
143	char		cursor_start;		/* cursor start line # */
144	char		cursor_end;		/* cursor end line # */
145	u_char		border;			/* border color */
146	u_short		bell_duration;
147	u_short		bell_pitch;
148	u_short 	status;			/* status (bitfield) */
149	u_short 	mode;			/* mode */
150	pid_t 		pid;			/* pid of controlling proc */
151	struct proc 	*proc;			/* proc* of controlling proc */
152	struct vt_mode 	smode;			/* switch mode */
153} scr_stat;
154
155typedef struct default_attr {
156	int             std_attr;               /* normal attributes */
157	int 		rev_attr;		/* reverse attributes */
158} default_attr;
159
160static default_attr user_default = {
161	(FG_LIGHTGREY | BG_BLACK) << 8,
162	(FG_BLACK | BG_LIGHTGREY) << 8
163};
164
165static default_attr kernel_default = {
166	(FG_WHITE | BG_BLACK) << 8,
167	(FG_BLACK | BG_LIGHTGREY) << 8
168};
169
170static	scr_stat	console[NCONS];
171static	scr_stat	*cur_console = &console[0];
172static	scr_stat	*new_scp, *old_scp;
173static	term_stat	kernel_console;
174static	default_attr	*current_default;
175static	int 		console_buffer_count;
176static	char 		console_buffer[CONSOLE_BUFSIZE];
177static	int		switch_in_progress = 0;
178static 	u_short	 	*crtat = 0;
179static	u_int		crtc_addr = MONO_BASE;
180static	char		crtc_vga = 0;
181static 	u_char		shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
182static 	u_char		nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
183static	char		*font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
184static  int		fonts_loaded = 0;
185static	char		palette[3*256];
186static 	const u_int 	n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
187static	int 		cur_cursor_pos = -1;
188static	char 		in_putc = 0;
189static	char	 	polling = 0;
190#if ASYNCH
191static  u_char		kbd_reply = 0;
192#endif
193static	int	 	delayed_next_scr;
194static	char		saved_console = -1;	/* saved console number	*/
195static	long		scrn_blank_time = 0;	/* screen saver timeout value */
196static	int		scrn_blanked = 0;	/* screen saver active flag */
197static	int		scrn_saver = 0;		/* screen saver routine */
198static	long 		scrn_time_stamp;
199static  u_char		scr_map[256];
200
201/* function prototypes */
202int pcprobe(struct isa_device *dev);
203int pcattach(struct isa_device *dev);
204int pcopen(dev_t dev, int flag, int mode, struct proc *p);
205int pcclose(dev_t dev, int flag, int mode, struct proc *p);
206int pcread(dev_t dev, struct uio *uio, int flag);
207int pcwrite(dev_t dev, struct uio *uio, int flag);
208int pcparam(struct tty *tp, struct termios *t);
209int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
210void pcxint(dev_t dev);
211void pcstart(struct tty *tp);
212void pccnprobe(struct consdev *cp);
213void pccninit(struct consdev *cp);
214void pccnputc(dev_t dev, char c);
215int pccngetc(dev_t dev);
216void scintr(int unit);
217int pcmmap(dev_t dev, int offset, int nprot);
218u_int sgetc(int noblock);
219int getchar(void);
220static void scinit(void);
221static void scput(u_char c);
222static u_int scgetc(int noblock);
223static struct tty *get_tty_ptr(dev_t dev);
224static scr_stat *get_scr_stat(dev_t dev);
225static int get_scr_num();
226static void cursor_shape(int start, int end);
227static void get_cursor_shape(int *start, int *end);
228static void cursor_pos(int force);
229static void clear_screen(scr_stat *scp);
230static int switch_scr(u_int next_scr);
231static void exchange_scr(void);
232static void move_crsr(scr_stat *scp, int x, int y);
233static void move_up(u_short *s, u_short *d, u_int len);
234static void move_down(u_short *s, u_short *d, u_int len);
235static void scan_esc(scr_stat *scp, u_char c);
236static void ansi_put(scr_stat *scp, u_char c);
237static u_char *get_fstr(u_int c, u_int *len);
238static void update_leds(int which);
239static void kbd_wait(void);
240static void kbd_cmd(u_char command);
241static void set_mode(scr_stat *scp);
242static void set_border(int color);
243static void set_vgaregs(char *modetable);
244static void copy_font(int direction, int segment, int size, char* font);
245static void save_palette(void);
246static void load_palette(void);
247
248/* available screen savers */
249static void none_saver(int test);
250static void blank_saver(int test);
251static void fade_saver(int test);
252static void star_saver(int test);
253static void snake_saver(int test);
254static void green_saver(int test);
255
256static const struct {
257	char	*name;
258	void	(*routine)();
259} screen_savers[] = {
260	{ "none",	none_saver },	/* 0 */
261	{ "blank",	blank_saver },	/* 1 */
262	{ "fade",	fade_saver },	/* 2 */
263	{ "star",	star_saver },	/* 3 */
264	{ "snake",	snake_saver },	/* 4 */
265	{ "green",	green_saver },	/* 5 */
266};
267#define SCRN_SAVER(arg)	(*screen_savers[scrn_saver].routine)(arg)
268#define NUM_SCRN_SAVERS	(sizeof(screen_savers) / sizeof(screen_savers[0]))
269
270/* OS specific stuff */
271#if 0
272#define VIRTUAL_TTY(x)	(pccons[x] = ttymalloc(pccons[x]))
273#define	CONSOLE_TTY	(pccons[NCONS] = ttymalloc(pccons[NCONS]))
274struct	tty 		*pccons[NCONS+1];
275#else
276#define VIRTUAL_TTY(x)	&pccons[x]
277#define	CONSOLE_TTY	&pccons[NCONS]
278struct	tty 		pccons[NCONS+1];
279#endif
280#define	timeout_t	timeout_func_t
281#define	MONO_BUF	(KERNBASE+0xB0000)
282#define	CGA_BUF		(KERNBASE+0xB8000)
283u_short			*Crtat = (u_short *)MONO_BUF;
284void 	consinit(void) 	{scinit();}
285extern  char 		*video_mode_ptr;
286int     color_display = -1;
287
288struct	isa_driver scdriver = {
289	pcprobe, pcattach, "sc", 1
290};
291
292int
293pcprobe(struct isa_device *dev)
294{
295	int i, retries = 5;
296	unsigned char val;
297
298	/* Enable interrupts and keyboard controller */
299	kbd_wait();
300	outb(KB_STAT, KB_WRITE);
301	kbd_wait();
302	outb(KB_DATA, KB_MODE);
303
304	/* flush any noise in the buffer */
305	while (inb(KB_STAT) & KB_BUF_FULL) {
306		DELAY(10);
307		(void) inb(KB_DATA);
308	}
309
310	/* Reset keyboard hardware */
311	while (retries--) {
312		kbd_wait();
313		outb(KB_DATA, KB_RESET);
314		for (i=0; i<100000; i++) {
315			DELAY(10);
316			val = inb(KB_DATA);
317			if (val == KB_ACK || val == KB_ECHO)
318				goto gotres;
319			if (val == KB_RESEND)
320				break;
321		}
322	}
323gotres:
324	if (!retries)
325		printf("scprobe: keyboard won't accept RESET command\n");
326	else {
327gotack:
328		DELAY(10);
329		while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
330		DELAY(10);
331		val = inb(KB_DATA);
332		if (val == KB_ACK)
333			goto gotack;
334		if (val != KB_RESET_DONE)
335			printf("scprobe: keyboard RESET failed %02x\n", val);
336	}
337	return (IO_KBDSIZE);
338}
339
340int
341pcattach(struct isa_device *dev)
342{
343	int i;
344	struct scr_stat *scp;
345
346	printf("sc%d: ", dev->id_unit);
347	if (crtc_vga)
348		if (crtc_addr == MONO_BASE)
349			printf("VGA mono");
350		else
351			printf("VGA color");
352	else
353		if (crtc_addr == MONO_BASE)
354			printf("MDA/hercules");
355		else
356			printf("CGA/EGA");
357	if (NCONS > 1)
358		printf(" <%d virtual consoles>\n", NCONS);
359	else
360		printf("\n");
361	if (crtc_vga) {
362#if defined(HARDFONTS)
363		font_8 = font_8x8;
364		font_14 = font_8x14;
365		font_16 = font_8x16;
366		fonts_loaded = FONT_8_LOADED|FONT_14_LOADED|FONT_16_LOADED;
367		copy_font(LOAD, 1, 8, font_8);
368		copy_font(LOAD, 2, 14, font_14);
369		copy_font(LOAD, 0, 16, font_16);
370#else
371		font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
372		font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
373		font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
374		copy_font(SAVE, 0, 16, font_16);
375		fonts_loaded = FONT_16_LOADED;
376#endif
377		save_palette();
378	}
379	for (i = 0; i < NCONS; i++) {
380		scp = &console[i];
381		scp->scr_buf = (u_short *)malloc(COL*ROW*2, M_DEVBUF, M_NOWAIT);
382		if (i > 0) {
383			scp->crt_base = scp->crtat = scp->scr_buf;
384			clear_screen(scp);
385		}
386	}
387	/* get cursor going */
388	cursor_pos(1);
389	update_leds(console[0].status);
390	return 0;
391}
392
393static struct tty
394*get_tty_ptr(dev_t dev)
395{
396	int unit = minor(dev);
397
398	if (unit > NCONS)
399		return(NULL);
400	if (unit == NCONS)
401		return(CONSOLE_TTY);
402	return(VIRTUAL_TTY(unit));
403}
404
405static scr_stat
406*get_scr_stat(dev_t dev)
407{
408	int unit = minor(dev);
409
410	if (unit > NCONS)
411		return(NULL);
412	if (unit == NCONS)
413		return(&console[0]);
414	return(&console[unit]);
415}
416
417static int
418get_scr_num()
419{
420	int i = 0;
421
422	while ((i < NCONS) && (cur_console != &console[i])) i++;
423	return i < NCONS ? i : 0;
424}
425
426int
427pcopen(dev_t dev, int flag, int mode, struct proc *p)
428{
429	struct tty *tp = get_tty_ptr(dev);
430
431	if (!tp)
432		return(ENXIO);
433
434	tp->t_oproc = pcstart;
435	tp->t_param = pcparam;
436	tp->t_dev = dev;
437	if (!(tp->t_state & TS_ISOPEN)) {
438		ttychars(tp);
439		tp->t_iflag = TTYDEF_IFLAG;
440		tp->t_oflag = TTYDEF_OFLAG;
441		tp->t_cflag = TTYDEF_CFLAG;
442		tp->t_lflag = TTYDEF_LFLAG;
443		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
444		pcparam(tp, &tp->t_termios);
445		ttsetwater(tp);
446	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
447		return(EBUSY);
448	tp->t_state |= TS_CARR_ON;
449	tp->t_cflag |= CLOCAL;
450	return((*linesw[tp->t_line].l_open)(dev, tp));
451}
452
453int
454pcclose(dev_t dev, int flag, int mode, struct proc *p)
455{
456	struct tty *tp = get_tty_ptr(dev);
457	struct scr_stat *scp;
458
459	if (!tp)
460		return(ENXIO);
461	if (minor(dev) < NCONS) {
462		scp = get_scr_stat(tp->t_dev);
463		if (scp->status & SWITCH_WAIT_ACQ)
464			wakeup((caddr_t)&scp->smode);
465		scp->pid = 0;
466		scp->proc = NULL;
467		scp->smode.mode = VT_AUTO;
468	}
469	(*linesw[tp->t_line].l_close)(tp, flag);
470	ttyclose(tp);
471	return(0);
472}
473
474int
475pcread(dev_t dev, struct uio *uio, int flag)
476{
477	struct tty *tp = get_tty_ptr(dev);
478
479	if (!tp)
480		return(ENXIO);
481	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
482}
483
484int
485pcwrite(dev_t dev, struct uio *uio, int flag)
486{
487	struct tty *tp = get_tty_ptr(dev);
488
489	if (!tp)
490		return(ENXIO);
491	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
492}
493
494void
495scintr(int unit)
496{
497	static struct tty *cur_tty;
498	int c, len;
499	u_char *cp;
500
501	/* make screensaver happy */
502	scrn_time_stamp = time.tv_sec;
503	if (scrn_blanked)
504		SCRN_SAVER(0);
505
506	c = scgetc(1);
507
508	cur_tty = VIRTUAL_TTY(get_scr_num());
509	if (!(cur_tty->t_state & TS_ISOPEN))
510		cur_tty = CONSOLE_TTY;
511
512	if (!(cur_tty->t_state & TS_ISOPEN) || polling)
513		return;
514
515	switch (c & 0xff00) {
516	case 0x0000: /* normal key */
517		(*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
518		break;
519	case NOKEY:	/* nothing there */
520		break;
521	case FKEY:	/* function key, return string */
522		if (cp = get_fstr((u_int)c, (u_int *)&len)) {
523			while (len-- >  0)
524				(*linesw[cur_tty->t_line].l_rint)
525					(*cp++ & 0xFF, cur_tty);
526		}
527		break;
528	case MKEY:	/* meta is active, prepend ESC */
529		(*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
530		(*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
531		break;
532	}
533}
534
535int
536pcparam(struct tty *tp, struct termios *t)
537{
538	int cflag = t->c_cflag;
539
540	/* and copy to tty */
541	tp->t_ispeed = t->c_ispeed;
542	tp->t_ospeed = t->c_ospeed;
543	tp->t_cflag = cflag;
544	return 0;
545}
546
547int
548pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
549{
550	int i, error;
551	struct tty *tp;
552	struct trapframe *fp;
553	scr_stat *scp;
554
555	tp = get_tty_ptr(dev);
556	if (!tp)
557		return ENXIO;
558	scp = get_scr_stat(tp->t_dev);
559
560	switch (cmd) {	/* process console hardware related ioctl's */
561
562	case GIO_ATTR:		/* get current attributes */
563		*(int*)data = scp->term.cur_attr;
564		return 0;
565
566	case GIO_COLOR:		/* is this a color console ? */
567		if (crtc_addr == COLOR_BASE)
568			*(int*)data = 1;
569		else
570			*(int*)data = 0;
571		return 0;
572
573	case CONS_CURRENT:	/* get current adapter type */
574		if (crtc_vga)
575			*(int*)data = KD_VGA;
576		else
577			if (crtc_addr == MONO_BASE)
578				*(int*)data = KD_MONO;
579			else
580				*(int*)data = KD_CGA;
581		return 0;
582
583	case CONS_GET:		/* get current video mode */
584		*(int*)data = scp->mode;
585		return 0;
586
587	case CONS_BLANKTIME:	/* set screen saver timeout (0 = no saver) */
588		scrn_blank_time = *(int*)data;
589		return 0;
590
591#define	SAVER(p) ((ssaver_t *)(p))
592	case CONS_SSAVER:	/* set screen saver */
593		if (SAVER(data)->num < 0
594		    || SAVER(data)->num >= NUM_SCRN_SAVERS)
595			return EIO;
596		SCRN_SAVER(0);
597		scrn_saver = SAVER(data)->num;
598		scrn_blank_time = SAVER(data)->time;
599		return 0;
600
601	case CONS_GSAVER:	/* get screen saver info */
602		if (SAVER(data)->num < 0)
603			SAVER(data)->num = scrn_saver;
604		else if (SAVER(data)->num >= NUM_SCRN_SAVERS)
605			return EIO;
606		SAVER(data)->time = scrn_blank_time;
607		strcpy(SAVER(data)->name, screen_savers[SAVER(data)->num].name);
608		return 0;
609
610	case CONS_GETINFO:	/* get current (virtual) console info */
611	{
612		vid_info_t *ptr = (vid_info_t*)data;
613		if (ptr->size == sizeof(struct vid_info)) {
614			ptr->m_num = get_scr_num();
615			ptr->mv_col = scp->xpos;
616			ptr->mv_row = scp->ypos;
617			ptr->mv_csz = scp->xsize;
618			ptr->mv_rsz = scp->ysize;
619			ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
620			ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
621			ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
622			ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
623			ptr->mv_grfc.fore = 0;		/* not supported */
624			ptr->mv_grfc.back = 0;		/* not supported */
625			ptr->mv_ovscan = scp->border;
626			ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
627			return 0;
628		}
629		return EINVAL;
630	}
631
632	case CONS_GETVERS:	/* get version number */
633		*(int*)data = 0x103;	/* version 1.3 */
634		return 0;
635
636        case SW_VGA_C40x25:  case SW_VGA_C80x25:	/* VGA TEXT MODES */
637        case SW_VGA_M80x25:
638        case SW_VGA_C80x50:  case SW_VGA_M80x50:
639        case SW_B40x25:     case SW_C40x25:
640        case SW_B80x25:     case SW_C80x25:
641        case SW_ENH_B40x25: case SW_ENH_C40x25:
642        case SW_ENH_B80x25: case SW_ENH_C80x25:
643        case SW_ENH_B80x43: case SW_ENH_C80x43:
644
645        	if (!crtc_vga)
646        		return ENXIO;
647		cmd &= 0xFF;
648		i = cmd < M_VGA_C80x50 ?
649		    *(video_mode_ptr + (cmd*64) + 2) : 0x08;
650		switch (i) {
651		default:
652		case 0x08:
653			if (!(fonts_loaded & FONT_8_LOADED))
654				return EINVAL;
655			break;
656		case 0x0E:
657			if (!(fonts_loaded & FONT_14_LOADED))
658				return EINVAL;
659			break;
660		case 0x10:
661			if (!(fonts_loaded & FONT_16_LOADED))
662				return EINVAL;
663			break;
664		}
665		scp->mode = cmd;
666            	scp->status &= ~UNKNOWN_MODE;	/* text mode */
667		if (scp->mode < M_VGA_C80x50) {
668            		scp->xsize = *(video_mode_ptr + (scp->mode*64));
669            		scp->ysize = *(video_mode_ptr + (scp->mode*64) + 1) + 1;
670		}
671		else switch (scp->mode) {
672			case M_VGA_C80x50: case M_VGA_M80x50:
673				scp->xsize = 80;
674				scp->ysize = 50;
675				break;
676        		case M_ENH_B80x43: case M_ENH_C80x43:
677				scp->xsize = 80;
678				scp->ysize = 43;
679				break;
680		}
681		free(scp->scr_buf, M_DEVBUF);
682		scp->scr_buf = (u_short *)malloc(scp->xsize * scp->ysize * 2,
683					     M_DEVBUF, M_NOWAIT);
684		if (scp == cur_console)
685            		set_mode(scp);
686		else
687			scp->crt_base = scp->scr_buf;
688            	clear_screen(scp);
689		if (tp->t_winsize.ws_col != scp->xsize
690		    || tp->t_winsize.ws_row != scp->ysize) {
691			tp->t_winsize.ws_col = scp->xsize;
692			tp->t_winsize.ws_row = scp->ysize;
693			pgsignal(tp->t_pgrp, SIGWINCH, 1);
694		}
695            	return 0;
696
697        /* GRAPHICS MODES */
698        case SW_BG320:      case SW_CG320:      case SW_BG640:
699        case SW_CG320_D:    case SW_CG640_E:
700        case SW_CG640x350:  case SW_ENH_CG640:
701        case SW_BG640x480:  case SW_CG640x480:  case SW_VGA_CG320:
702
703	    	scp->mode = cmd & 0xFF;
704            	scp->status |= UNKNOWN_MODE;	/* graphics mode */
705		if (scp == cur_console)
706            		set_mode(scp);
707            	/* clear_graphics();*/
708            	return 0;
709
710	case VT_SETMODE:	/* set screen switcher mode */
711		bcopy(data, &scp->smode, sizeof(struct vt_mode));
712		if (scp->smode.mode == VT_PROCESS) {
713			scp->proc = p;
714			scp->pid = scp->proc->p_pid;
715		}
716		return 0;
717
718	case VT_GETMODE:	/* get screen switcher mode */
719		bcopy(&scp->smode, data, sizeof(struct vt_mode));
720		return 0;
721
722	case VT_RELDISP:	/* screen switcher ioctl */
723		switch(*data) {
724		case VT_FALSE:	/* user refuses to release screen, abort */
725			if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
726				old_scp->status &= ~SWITCH_WAIT_REL;
727				switch_in_progress = 0;
728				return 0;
729			}
730			return EINVAL;
731
732		case VT_TRUE:	/* user has released screen, go on */
733			if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
734				scp->status &= ~SWITCH_WAIT_REL;
735				exchange_scr();
736				if (new_scp->smode.mode == VT_PROCESS) {
737					new_scp->status |= SWITCH_WAIT_ACQ;
738					psignal(new_scp->proc,
739						new_scp->smode.acqsig);
740				}
741				else
742					switch_in_progress = 0;
743				return 0;
744			}
745			return EINVAL;
746
747		case VT_ACKACQ:	/* acquire acknowledged, switch completed */
748			if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
749				scp->status &= ~SWITCH_WAIT_ACQ;
750				switch_in_progress = 0;
751				return 0;
752			}
753			return EINVAL;
754
755		default:
756			return EINVAL;
757		}
758		/* NOT REACHED */
759
760	case VT_OPENQRY:	/* return free virtual console */
761 		for (i = 0; i < NCONS; i++) {
762			tp = VIRTUAL_TTY(i);
763 			if (!(tp->t_state & TS_ISOPEN)) {
764 				*data = i + 1;
765 				return 0;
766 			}
767		}
768 		return EINVAL;
769
770	case VT_ACTIVATE:	/* switch to screen *data */
771		return switch_scr((*data) - 1);
772
773	case VT_WAITACTIVE:	/* wait for switch to occur */
774		if (*data > NCONS)
775			return EINVAL;
776		if (minor(dev) == (*data) - 1)
777			return 0;
778		if (*data == 0) {
779			if (scp == cur_console)
780				return 0;
781			while ((error=tsleep((caddr_t)&scp->smode,
782			    	PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
783		}
784		else
785			while ((error=tsleep(
786      				(caddr_t)&console[*(data-1)].smode,
787			    	PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
788		return error;
789
790	case VT_GETACTIVE:
791		*data = get_scr_num()+1;
792		return 0;
793
794	case KDENABIO:		/* allow io operations */
795	 	fp = (struct trapframe *)p->p_md.md_regs;
796	 	fp->tf_eflags |= PSL_IOPL;
797		return 0;
798
799	case KDDISABIO:		/* disallow io operations (default) */
800	 	fp = (struct trapframe *)p->p_md.md_regs;
801	 	fp->tf_eflags &= ~PSL_IOPL;
802	 	return 0;
803
804        case KDSETMODE:		/* set current mode of this (virtual) console */
805		switch (*data) {
806		case KD_TEXT:	/* switch to TEXT (known) mode */
807				/* restore fonts & palette ! */
808			if (crtc_vga) {
809				if (fonts_loaded & FONT_16_LOADED)
810					copy_font(LOAD, 0, 16, font_16);
811				if (fonts_loaded & FONT_8_LOADED)
812					copy_font(LOAD, 1, 8, font_8);
813				if (fonts_loaded & FONT_14_LOADED)
814					copy_font(LOAD, 2, 14, font_14);
815				load_palette();
816			}
817			/* FALL THROUGH */
818
819		case KD_TEXT1:	/* switch to TEXT (known) mode */
820				/* no restore fonts & palette */
821			scp->status &= ~UNKNOWN_MODE;
822			set_mode(scp);
823			clear_screen(scp);
824			return 0;
825
826		case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */
827			scp->status |= UNKNOWN_MODE;
828			return 0;
829		default:
830			return EINVAL;
831		}
832		/* NOT REACHED */
833
834	case KDGETMODE:		/* get current mode of this (virtual) console */
835		*data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
836		return 0;
837
838	case KDSBORDER:		/* set border color of this (virtual) console */
839		if (!crtc_vga)
840			return ENXIO;
841		scp->border = *data;
842		if (scp == cur_console)
843			set_border(scp->border);
844		return 0;
845
846	case KDSKBSTATE:	/* set keyboard state (locks) */
847		if (*data >= 0 && *data <= LOCK_KEY_MASK) {
848			scp->status &= ~LOCK_KEY_MASK;
849			scp->status |= *data;
850			if (scp == cur_console)
851				update_leds(scp->status);
852			return 0;
853		}
854		return EINVAL;
855
856	case KDGKBSTATE:	/* get keyboard state (locks) */
857		*data = scp->status & LOCK_KEY_MASK;
858		return 0;
859
860	case KDSETRAD:		/* set keyboard repeat & delay rates */
861		if (*data & 0x80)
862			return EINVAL;
863		i = spltty();
864		kbd_cmd(KB_SETRAD);
865		kbd_cmd(*data);
866		splx(i);
867		return 0;
868
869	case KDSKBMODE:		/* set keyboard mode */
870		switch (*data) {
871		case K_RAW:	/* switch to RAW scancode mode */
872			scp->status |= KBD_RAW_MODE;
873			return 0;
874
875		case K_XLATE:	/* switch to XLT ascii mode */
876			if (scp == cur_console && scp->status == KBD_RAW_MODE)
877				shfts = ctls = alts = agrs = metas = 0;
878			scp->status &= ~KBD_RAW_MODE;
879			return 0;
880		default:
881			return EINVAL;
882		}
883		/* NOT REACHED */
884
885	case KDGKBMODE:		/* get keyboard mode */
886		*data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
887		return 0;
888
889	case KDMKTONE:		/* sound the bell */
890		if (scp == cur_console)
891			sysbeep(scp->bell_pitch, scp->bell_duration);
892		return 0;
893
894	case KIOCSOUND:		/* make tone (*data) hz */
895		if (scp == cur_console) {
896			if (*(int*)data) {
897			int pitch = TIMER_FREQ/(*(int*)data);
898				/* set command for counter 2, 2 byte write */
899				if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
900					return EBUSY;
901				}
902				/* set pitch */
903				outb(TIMER_CNTR2, pitch);
904				outb(TIMER_CNTR2, (pitch>>8));
905				/* enable counter 2 output to speaker */
906				outb(IO_PPI, inb(IO_PPI) | 3);
907			}
908			else {
909				/* disable counter 2 output to speaker */
910				outb(IO_PPI, inb(IO_PPI) & 0xFC);
911				release_timer2();
912			}
913		}
914		return 0;
915
916	case KDGKBTYPE:		/* get keyboard type */
917		*data = 0;	/* type not known (yet) */
918		return 0;
919
920	case KDSETLED:		/* set keyboard LED status */
921		if (*data >= 0 && *data <= LED_MASK) {
922			scp->status &= ~LED_MASK;
923			scp->status |= *data;
924			if (scp == cur_console)
925				update_leds(scp->status);
926			return 0;
927		}
928		return EINVAL;
929
930	case KDGETLED:		/* get keyboard LED status */
931		*data = scp->status & LED_MASK;
932		return 0;
933
934	case GETFKEY:		/* get functionkey string */
935		if (*(u_short*)data < n_fkey_tab) {
936		 	fkeyarg_t *ptr = (fkeyarg_t*)data;
937			bcopy(&fkey_tab[ptr->keynum].str,
938			      ptr->keydef,
939			      fkey_tab[ptr->keynum].len);
940			ptr->flen = fkey_tab[ptr->keynum].len;
941			return 0;
942		}
943		else
944			return EINVAL;
945
946	case SETFKEY:		/* set functionkey string */
947		if (*(u_short*)data < n_fkey_tab) {
948		 	fkeyarg_t *ptr = (fkeyarg_t*)data;
949			bcopy(ptr->keydef,
950			      &fkey_tab[ptr->keynum].str,
951			      min(ptr->flen, MAXFK));
952			fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
953			return 0;
954		}
955		else
956			return EINVAL;
957
958	case GIO_SCRNMAP: 	/* get output translation table */
959		bcopy(&scr_map, data, sizeof(scr_map));
960		return 0;
961
962	case PIO_SCRNMAP:	/* set output translation table */
963		bcopy(data, &scr_map, sizeof(scr_map));
964		return 0;
965
966	case GIO_KEYMAP: 	/* get keyboard translation table */
967		bcopy(&key_map, data, sizeof(key_map));
968		return 0;
969
970	case PIO_KEYMAP:	/* set keyboard translation table */
971		bcopy(data, &key_map, sizeof(key_map));
972		return 0;
973
974	case PIO_FONT8x8:	/* set 8x8 dot font */
975		if (!crtc_vga)
976			return ENXIO;
977		bcopy(data, font_8, 8*256);
978		fonts_loaded |= FONT_8_LOADED;
979		copy_font(LOAD, 1, 8, font_8);
980		return 0;
981
982	case GIO_FONT8x8:	/* get 8x8 dot font */
983		if (!crtc_vga)
984			return ENXIO;
985		if (fonts_loaded & FONT_8_LOADED) {
986			bcopy(font_8, data, 8*256);
987			return 0;
988		}
989		else
990			return ENXIO;
991
992	case PIO_FONT8x14:	/* set 8x14 dot font */
993		if (!crtc_vga)
994			return ENXIO;
995		bcopy(data, font_14, 14*256);
996		fonts_loaded |= FONT_14_LOADED;
997		copy_font(LOAD, 2, 14, font_14);
998		return 0;
999
1000	case GIO_FONT8x14:	/* get 8x14 dot font */
1001		if (!crtc_vga)
1002			return ENXIO;
1003		if (fonts_loaded & FONT_14_LOADED) {
1004			bcopy(font_14, data, 14*256);
1005			return 0;
1006		}
1007		else
1008			return ENXIO;
1009
1010	case PIO_FONT8x16:	/* set 8x16 dot font */
1011		if (!crtc_vga)
1012			return ENXIO;
1013		bcopy(data, font_16, 16*256);
1014		fonts_loaded |= FONT_16_LOADED;
1015		copy_font(LOAD, 0, 16, font_16);
1016		return 0;
1017
1018	case GIO_FONT8x16:	/* get 8x16 dot font */
1019		if (!crtc_vga)
1020			return ENXIO;
1021		if (fonts_loaded & FONT_16_LOADED) {
1022			bcopy(font_16, data, 16*256);
1023			return 0;
1024		}
1025		else
1026			return ENXIO;
1027
1028	case CONSOLE_X_MODE_ON:	/* just to be compatible */
1029		if (saved_console < 0) {
1030			saved_console = get_scr_num();
1031			switch_scr(minor(dev));
1032	 		fp = (struct trapframe *)p->p_md.md_regs;
1033	 		fp->tf_eflags |= PSL_IOPL;
1034			scp->status |= UNKNOWN_MODE;
1035			scp->status |= KBD_RAW_MODE;
1036			return 0;
1037		}
1038		return EAGAIN;
1039
1040	case CONSOLE_X_MODE_OFF:/* just to be compatible */
1041	 	fp = (struct trapframe *)p->p_md.md_regs;
1042	 	fp->tf_eflags &= ~PSL_IOPL;
1043		if (crtc_vga) {
1044			if (fonts_loaded & FONT_16_LOADED)
1045				copy_font(LOAD, 0, 16, font_16);
1046			if (fonts_loaded & FONT_8_LOADED)
1047				copy_font(LOAD, 1, 8, font_8);
1048			if (fonts_loaded & FONT_14_LOADED)
1049				copy_font(LOAD, 2, 14, font_14);
1050			load_palette();
1051		}
1052		scp->status &= ~UNKNOWN_MODE;
1053		set_mode(scp);
1054		clear_screen(scp);
1055		scp->status &= ~KBD_RAW_MODE;
1056		switch_scr(saved_console);
1057		saved_console = -1;
1058		return 0;
1059
1060	 case CONSOLE_X_BELL:	/* more compatibility */
1061                /*
1062                 * if set, data is a pointer to a length 2 array of
1063                 * integers. data[0] is the pitch in Hz and data[1]
1064                 * is the duration in msec.
1065                 */
1066                if (data)
1067	    		sysbeep(TIMER_FREQ/((int*)data)[0],
1068				((int*)data)[1]*hz/1000);
1069                else
1070			sysbeep(scp->bell_pitch, scp->bell_duration);
1071                return 0;
1072
1073	default:
1074		break;
1075	}
1076
1077	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1078	if (error >= 0)
1079		return(error);
1080	error = ttioctl(tp, cmd, data, flag);
1081	if (error >= 0)
1082		return(error);
1083	return(ENOTTY);
1084}
1085
1086void
1087pcxint(dev_t dev)
1088{
1089	struct tty *tp = get_tty_ptr(dev);
1090
1091	if (!tp)
1092		return;
1093	tp->t_state &= ~TS_BUSY;
1094	if (tp->t_line)
1095		(*linesw[tp->t_line].l_start)(tp);
1096	else
1097		pcstart(tp);
1098}
1099
1100void
1101pcstart(struct tty *tp)
1102{
1103	struct clist *rbp;
1104	int i, s, len;
1105	u_char buf[PCBURST];
1106	scr_stat *scp = get_scr_stat(tp->t_dev);
1107
1108	if (scp->status & SLKED)
1109		return;
1110	s = spltty();
1111	if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
1112		tp->t_state |= TS_BUSY;
1113		splx(s);
1114		rbp = &tp->t_outq;
1115		while (rbp->c_cc) {
1116			len = q_to_b(rbp, buf, PCBURST);
1117			for (i=0; i<len; i++)
1118				if (buf[i]) ansi_put(scp, buf[i]);
1119		}
1120		s = spltty();
1121		tp->t_state &= ~TS_BUSY;
1122#if 0
1123		if (rbp->c_cc) {
1124			tp->t_state |= TS_TIMEOUT;
1125			timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
1126		}
1127#endif
1128		if (rbp->c_cc <= tp->t_lowat) {
1129			if (tp->t_state & TS_ASLEEP) {
1130				tp->t_state &= ~TS_ASLEEP;
1131				wakeup((caddr_t)rbp);
1132			}
1133			selwakeup(&tp->t_wsel);
1134		}
1135	}
1136	splx(s);
1137}
1138
1139void
1140pccnprobe(struct consdev *cp)
1141{
1142	int maj;
1143
1144	/* locate the major number */
1145	for (maj = 0; maj < nchrdev; maj++)
1146		if ((void*)cdevsw[maj].d_open == (void*)pcopen)
1147			break;
1148
1149	/* initialize required fields */
1150	cp->cn_dev = makedev(maj, NCONS);
1151	cp->cn_pri = CN_INTERNAL;
1152}
1153
1154void
1155pccninit(struct consdev *cp)
1156{
1157	scinit();
1158}
1159
1160void
1161pccnputc(dev_t dev, char c)
1162{
1163	if (c == '\n')
1164		scput('\r');
1165	scput(c);
1166	if (cur_console == &console[0]) {
1167	int 	pos = cur_console->crtat - cur_console->crt_base;
1168		if (pos != cur_cursor_pos) {
1169			cur_cursor_pos = pos;
1170			outb(crtc_addr,14);
1171			outb(crtc_addr+1,pos >> 8);
1172			outb(crtc_addr,15);
1173			outb(crtc_addr+1,pos&0xff);
1174		}
1175	}
1176}
1177
1178int
1179pccngetc(dev_t dev)
1180{
1181	int s = spltty();		/* block scintr while we poll */
1182	int c = scgetc(0);
1183	splx(s);
1184	if (c == '\r') c = '\n';
1185	return(c);
1186}
1187
1188static void
1189none_saver(int test)
1190{
1191}
1192
1193static void
1194fade_saver(int test)
1195{
1196	static int count = 0;
1197	int i;
1198
1199	if (test) {
1200		scrn_blanked = 1;
1201		if (count < 64) {
1202  			outb(PIXMASK, 0xFF);		/* no pixelmask */
1203  			outb(PALWADR, 0x00);
1204    			outb(PALDATA, 0);
1205    			outb(PALDATA, 0);
1206    			outb(PALDATA, 0);
1207  			for (i = 3; i < 768; i++) {
1208  				if (palette[i] - count > 15)
1209    					outb(PALDATA, palette[i]-count);
1210				else
1211    					outb(PALDATA, 15);
1212			}
1213			inb(crtc_addr+6);		/* reset flip/flop */
1214			outb(ATC, 0x20);		/* enable palette */
1215			count++;
1216		}
1217	}
1218	else {
1219		count = scrn_blanked = 0;
1220		load_palette();
1221	}
1222}
1223
1224static void
1225blank_saver(int test)
1226{
1227	u_char val;
1228	if (test) {
1229		scrn_blanked = 1;
1230  		outb(TSIDX, 0x01); val = inb(TSREG);
1231		outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1232	}
1233	else {
1234		scrn_blanked = 0;
1235  		outb(TSIDX, 0x01); val = inb(TSREG);
1236		outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
1237	}
1238}
1239
1240static void
1241green_saver(int test)
1242{
1243	u_char val;
1244	if (test) {
1245		scrn_blanked = 1;
1246  		outb(TSIDX, 0x01); val = inb(TSREG);
1247		outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
1248		outb(crtc_addr, 0x17); val = inb(crtc_addr + 1);
1249		outb(crtc_addr + 1, val & ~0x80);
1250	}
1251	else {
1252		scrn_blanked = 0;
1253  		outb(TSIDX, 0x01); val = inb(TSREG);
1254		outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
1255                outb(crtc_addr, 0x17); val = inb(crtc_addr + 1);
1256                outb(crtc_addr + 1, val | 0x80);
1257	}
1258}
1259
1260#define NUM_STARS	50
1261
1262/*
1263 * Alternate saver that got its inspiration from a well known utility
1264 * package for an inferior^H^H^H^H^H^Hfamous OS.
1265 */
1266static void
1267star_saver(int test)
1268{
1269	scr_stat	*scp = cur_console;
1270	int		cell, i;
1271	char 		pattern[] = {"...........++++***   "};
1272	char		colors[] = {FG_DARKGREY, FG_LIGHTGREY,
1273				    FG_WHITE, FG_LIGHTCYAN};
1274	static u_short 	stars[NUM_STARS][2];
1275
1276	if (test) {
1277		if (!scrn_blanked) {
1278			bcopy(Crtat, scp->scr_buf,
1279			      scp->xsize * scp->ysize * 2);
1280			fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
1281			      scp->xsize * scp->ysize);
1282			set_border(0);
1283			i = scp->ysize * scp->xsize + 5;
1284			outb(crtc_addr, 14);
1285			outb(crtc_addr+1, i >> 8);
1286			outb(crtc_addr, 15);
1287			outb(crtc_addr+1, i & 0xff);
1288			scrn_blanked = 1;
1289 			for(i=0; i<NUM_STARS; i++) {
1290  				stars[i][0] =
1291					random() % (scp->xsize*scp->ysize);
1292  				stars[i][1] = 0;
1293 			}
1294		}
1295   		cell = random() % NUM_STARS;
1296		*((u_short*)(Crtat + stars[cell][0])) =
1297			scr_map[pattern[stars[cell][1]]] |
1298			        colors[random()%sizeof(colors)] << 8;
1299		if ((stars[cell][1]+=(random()%4)) >= sizeof(pattern)-1) {
1300    			stars[cell][0] = random() % (scp->xsize*scp->ysize);
1301   			stars[cell][1] = 0;
1302		}
1303	}
1304	else {
1305		if (scrn_blanked) {
1306			bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
1307			cur_cursor_pos = -1;
1308			set_border(scp->border);
1309			scrn_blanked = 0;
1310		}
1311	}
1312}
1313
1314static void
1315snake_saver(int test)
1316{
1317	const char	saves[] = {"FreeBSD-2.0"};
1318	static u_char	*savs[sizeof(saves)-1];
1319	static int	dirx, diry;
1320	int		f;
1321	scr_stat	*scp = cur_console;
1322
1323	if (test) {
1324		if (!scrn_blanked) {
1325			bcopy(Crtat, scp->scr_buf,
1326			      scp->xsize * scp->ysize * 2);
1327			fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
1328			      Crtat, scp->xsize * scp->ysize);
1329			set_border(0);
1330			dirx = (scp->xpos ? 1 : -1);
1331			diry = (scp->ypos ?
1332				scp->xsize : -scp->xsize);
1333			for (f=0; f< sizeof(saves)-1; f++)
1334				savs[f] = (u_char *)Crtat + 2 *
1335					  (scp->xpos+scp->ypos*scp->xsize);
1336			*(savs[0]) = scr_map[*saves];
1337			f = scp->ysize * scp->xsize + 5;
1338			outb(crtc_addr, 14);
1339			outb(crtc_addr+1, f >> 8);
1340			outb(crtc_addr, 15);
1341			outb(crtc_addr+1, f & 0xff);
1342			scrn_blanked = 1;
1343		}
1344		if (scrn_blanked++ < 4)
1345			return;
1346		scrn_blanked = 1;
1347		*(savs[sizeof(saves)-2]) = scr_map[0x20];
1348		for (f=sizeof(saves)-2; f > 0; f--)
1349			savs[f] = savs[f-1];
1350		f = (savs[0] - (u_char *)Crtat) / 2;
1351		if ((f % scp->xsize) == 0 ||
1352		    (f % scp->xsize) == scp->xsize - 1 ||
1353		    (random() % 50) == 0)
1354			dirx = -dirx;
1355		if ((f / scp->xsize) == 0 ||
1356		    (f / scp->xsize) == scp->ysize - 1 ||
1357		    (random() % 20) == 0)
1358			diry = -diry;
1359		savs[0] += 2*dirx + 2*diry;
1360		for (f=sizeof(saves)-2; f>=0; f--)
1361			*(savs[f]) = scr_map[saves[f]];
1362	}
1363	else {
1364		if (scrn_blanked) {
1365			bcopy(scp->scr_buf, Crtat,
1366			      scp->xsize * scp->ysize * 2);
1367			cur_cursor_pos = -1;
1368			set_border(scp->border);
1369			scrn_blanked = 0;
1370		}
1371	}
1372}
1373
1374static void
1375cursor_shape(int start, int end)
1376{
1377	outb(crtc_addr, 10);
1378	outb(crtc_addr+1, start & 0xFF);
1379	outb(crtc_addr, 11);
1380	outb(crtc_addr+1, end & 0xFF);
1381}
1382
1383#if !defined(FAT_CURSOR)
1384static void
1385get_cursor_shape(int *start, int *end)
1386{
1387	outb(crtc_addr, 10);
1388	*start = inb(crtc_addr+1) & 0x1F;
1389	outb(crtc_addr, 11);
1390	*end = inb(crtc_addr+1) & 0x1F;
1391}
1392#endif
1393
1394static void
1395cursor_pos(int force)
1396{
1397	int pos;
1398
1399	if (cur_console->status & UNKNOWN_MODE)
1400		return;
1401	if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
1402		SCRN_SAVER(1);
1403	pos = cur_console->crtat - cur_console->crt_base;
1404	if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
1405		cur_cursor_pos = pos;
1406		outb(crtc_addr, 14);
1407		outb(crtc_addr+1, pos>>8);
1408		outb(crtc_addr, 15);
1409		outb(crtc_addr+1, pos&0xff);
1410	}
1411	timeout((timeout_t)cursor_pos, 0, hz/20);
1412}
1413
1414static void
1415clear_screen(scr_stat *scp)
1416{
1417	move_crsr(scp, 0, 0);
1418	fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
1419	       scp->xsize * scp->ysize);
1420}
1421
1422static int
1423switch_scr(u_int next_scr)
1424{
1425	if (switch_in_progress &&
1426	    (cur_console->proc != pfind(cur_console->pid)))
1427		switch_in_progress = 0;
1428
1429    	if (next_scr >= NCONS || switch_in_progress
1430	    || (cur_console->smode.mode == VT_AUTO
1431	       	&& cur_console->status & UNKNOWN_MODE)) {
1432		sysbeep(BELL_PITCH, BELL_DURATION);
1433		return EINVAL;
1434	}
1435
1436	/* is the wanted virtual console open ? */
1437	if (next_scr) {
1438		struct tty *tp = VIRTUAL_TTY(next_scr);
1439		if (!(tp->t_state & TS_ISOPEN)) {
1440			sysbeep(BELL_PITCH, BELL_DURATION);
1441			return EINVAL;
1442		}
1443	}
1444	if (in_putc) {		/* delay switch if in putc */
1445		delayed_next_scr = next_scr+1;
1446		return 0;
1447	}
1448	switch_in_progress = 1;
1449	old_scp = cur_console;
1450	new_scp = &console[next_scr];
1451	wakeup((caddr_t)&new_scp->smode);
1452	if (new_scp == old_scp) {
1453		switch_in_progress = 0;
1454		return 0;
1455	}
1456
1457	/* has controlling process died? */
1458	if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
1459		old_scp->smode.mode = VT_AUTO;
1460	if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
1461		new_scp->smode.mode = VT_AUTO;
1462
1463	/* check the modes and switch approbiatly */
1464	if (old_scp->smode.mode == VT_PROCESS) {
1465		old_scp->status |= SWITCH_WAIT_REL;
1466		psignal(old_scp->proc, old_scp->smode.relsig);
1467	}
1468	else {
1469		exchange_scr();
1470		if (new_scp->smode.mode == VT_PROCESS) {
1471			new_scp->status |= SWITCH_WAIT_ACQ;
1472			psignal(new_scp->proc, new_scp->smode.acqsig);
1473		}
1474		else
1475			switch_in_progress = 0;
1476	}
1477	return 0;
1478}
1479
1480static void
1481exchange_scr(void)
1482{
1483	bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
1484	old_scp->crt_base = old_scp->scr_buf;
1485	move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
1486	cur_console = new_scp;
1487	if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE))
1488		set_mode(new_scp);
1489	new_scp->crt_base = Crtat;
1490	move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
1491	bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
1492	update_leds(new_scp->status);
1493	if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
1494		if (fonts_loaded & FONT_16_LOADED)
1495			copy_font(LOAD, 0, 16, font_16);
1496		if (fonts_loaded & FONT_8_LOADED)
1497			copy_font(LOAD, 1, 8, font_8);
1498		if (fonts_loaded & FONT_14_LOADED)
1499			copy_font(LOAD, 2, 14, font_14);
1500		load_palette();
1501	}
1502	if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
1503		shfts = ctls = alts = agrs = metas = 0;
1504	delayed_next_scr = 0;
1505}
1506
1507static void
1508move_crsr(scr_stat *scp, int x, int y)
1509{
1510	if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
1511		return;
1512	scp->xpos = x;
1513	scp->ypos = y;
1514	scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
1515}
1516
1517static void
1518move_up(u_short *s, u_short *d, u_int len)
1519{
1520	s += len;
1521	d += len;
1522	while (len-- > 0)
1523		*--d = *--s;
1524}
1525
1526static void
1527move_down(u_short *s, u_short *d, u_int len)
1528{
1529	while (len-- > 0)
1530		*d++ = *s++;
1531}
1532
1533static void
1534scan_esc(scr_stat *scp, u_char c)
1535{
1536	static u_char ansi_col[16] =
1537		{0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
1538	int i, n;
1539	u_short *src, *dst, count;
1540
1541	if (scp->term.esc == 1) {
1542		switch (c) {
1543
1544		case '[': 	/* Start ESC [ sequence */
1545			scp->term.esc = 2;
1546			scp->term.last_param = -1;
1547			for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1548				scp->term.param[i] = 1;
1549			scp->term.num_param = 0;
1550			return;
1551
1552		case 'M':	/* Move cursor up 1 line, scroll if at top */
1553			if (scp->ypos > 0)
1554				move_crsr(scp, scp->xpos, scp->ypos - 1);
1555			else {
1556				move_up(scp->crt_base,
1557					scp->crt_base + scp->xsize,
1558					(scp->ysize - 1) * scp->xsize);
1559				fillw(scp->term.cur_attr | scr_map[0x20],
1560				      scp->crt_base, scp->xsize);
1561			}
1562			break;
1563#if notyet
1564		case 'Q':
1565			scp->term.esc = 4;
1566			break;
1567#endif
1568		case 'c':	/* Clear screen & home */
1569			clear_screen(scp);
1570			break;
1571		}
1572	}
1573	else if (scp->term.esc == 2) {
1574		if (c >= '0' && c <= '9') {
1575			if (scp->term.num_param < MAX_ESC_PAR) {
1576				if (scp->term.last_param != scp->term.num_param) {
1577					scp->term.last_param = scp->term.num_param;
1578					scp->term.param[scp->term.num_param] = 0;
1579				}
1580				else
1581					scp->term.param[scp->term.num_param] *= 10;
1582				scp->term.param[scp->term.num_param] += c - '0';
1583				return;
1584			}
1585		}
1586		scp->term.num_param = scp->term.last_param + 1;
1587		switch (c) {
1588
1589		case ';':
1590			if (scp->term.num_param < MAX_ESC_PAR)
1591				return;
1592			break;
1593
1594		case '=':
1595			scp->term.esc = 3;
1596			scp->term.last_param = -1;
1597			for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1598				scp->term.param[i] = 1;
1599			scp->term.num_param = 0;
1600			return;
1601
1602		case 'A': /* up n rows */
1603			n = scp->term.param[0]; if (n < 1) n = 1;
1604			move_crsr(scp, scp->xpos, scp->ypos - n);
1605			break;
1606
1607		case 'B': /* down n rows */
1608			n = scp->term.param[0]; if (n < 1) n = 1;
1609			move_crsr(scp, scp->xpos, scp->ypos + n);
1610			break;
1611
1612		case 'C': /* right n columns */
1613			n = scp->term.param[0]; if (n < 1) n = 1;
1614			move_crsr(scp, scp->xpos + n, scp->ypos);
1615			break;
1616
1617		case 'D': /* left n columns */
1618			n = scp->term.param[0]; if (n < 1) n = 1;
1619			move_crsr(scp, scp->xpos - n, scp->ypos);
1620			break;
1621
1622		case 'E': /* cursor to start of line n lines down */
1623			n = scp->term.param[0]; if (n < 1) n = 1;
1624			move_crsr(scp, 0, scp->ypos + n);
1625			break;
1626
1627		case 'F': /* cursor to start of line n lines up */
1628			n = scp->term.param[0]; if (n < 1) n = 1;
1629			move_crsr(scp, 0, scp->ypos - n);
1630			break;
1631
1632		case 'f': /* System V consoles .. */
1633		case 'H': /* Cursor move */
1634			if (scp->term.num_param == 0)
1635				move_crsr(scp, 0, 0);
1636			else if (scp->term.num_param == 2)
1637				move_crsr(scp, scp->term.param[1] - 1,
1638					  scp->term.param[0] - 1);
1639			break;
1640
1641		case 'J': /* Clear all or part of display */
1642			if (scp->term.num_param == 0)
1643				n = 0;
1644			else
1645				n = scp->term.param[0];
1646			switch (n) {
1647			case 0: /* clear form cursor to end of display */
1648				fillw(scp->term.cur_attr | scr_map[0x20],
1649				      scp->crtat, scp->crt_base +
1650				      scp->xsize * scp->ysize -
1651				      scp->crtat);
1652				break;
1653			case 1: /* clear from beginning of display to cursor */
1654				fillw(scp->term.cur_attr | scr_map[0x20],
1655				      scp->crt_base,
1656				      scp->crtat - scp->crt_base);
1657				break;
1658			case 2: /* clear entire display */
1659				clear_screen(scp);
1660				break;
1661			}
1662			break;
1663
1664		case 'K': /* Clear all or part of line */
1665			if (scp->term.num_param == 0)
1666				n = 0;
1667			else
1668				n = scp->term.param[0];
1669			switch (n) {
1670			case 0: /* clear form cursor to end of line */
1671				fillw(scp->term.cur_attr | scr_map[0x20],
1672				      scp->crtat, scp->xsize - scp->xpos);
1673				break;
1674			case 1: /* clear from beginning of line to cursor */
1675				fillw(scp->term.cur_attr|scr_map[0x20],
1676				      scp->crtat - (scp->xsize - scp->xpos),
1677				      (scp->xsize - scp->xpos) + 1);
1678				break;
1679			case 2: /* clear entire line */
1680				fillw(scp->term.cur_attr|scr_map[0x20],
1681				      scp->crtat - (scp->xsize - scp->xpos),
1682				      scp->xsize);
1683				break;
1684			}
1685			break;
1686
1687		case 'L':	/* Insert n lines */
1688			n = scp->term.param[0]; if (n < 1) n = 1;
1689			if (n > scp->ysize - scp->ypos)
1690				n = scp->ysize - scp->ypos;
1691			src = scp->crt_base + scp->ypos * scp->xsize;
1692			dst = src + n * scp->xsize;
1693			count = scp->ysize - (scp->ypos + n);
1694			move_up(src, dst, count * scp->xsize);
1695			fillw(scp->term.cur_attr | scr_map[0x20], src,
1696			      n * scp->xsize);
1697			break;
1698
1699		case 'M':	/* Delete n lines */
1700			n = scp->term.param[0]; if (n < 1) n = 1;
1701			if (n > scp->ysize - scp->ypos)
1702				n = scp->ysize - scp->ypos;
1703			dst = scp->crt_base + scp->ypos * scp->xsize;
1704			src = dst + n * scp->xsize;
1705			count = scp->ysize - (scp->ypos + n);
1706			move_down(src, dst, count * scp->xsize);
1707			src = dst + count * scp->xsize;
1708			fillw(scp->term.cur_attr | scr_map[0x20], src,
1709			      n * scp->xsize);
1710			break;
1711
1712		case 'P':	/* Delete n chars */
1713			n = scp->term.param[0]; if (n < 1) n = 1;
1714			if (n > scp->xsize - scp->xpos)
1715				n = scp->xsize - scp->xpos;
1716			dst = scp->crtat;
1717			src = dst + n;
1718			count = scp->xsize - (scp->xpos + n);
1719			move_down(src, dst, count);
1720			src = dst + count;
1721			fillw(scp->term.cur_attr | scr_map[0x20], src, n);
1722			break;
1723
1724		case '@':	/* Insert n chars */
1725			n = scp->term.param[0]; if (n < 1) n = 1;
1726			if (n > scp->xsize - scp->xpos)
1727				n = scp->xsize - scp->xpos;
1728			src = scp->crtat;
1729			dst = src + n;
1730			count = scp->xsize - (scp->xpos + n);
1731			move_up(src, dst, count);
1732			fillw(scp->term.cur_attr | scr_map[0x20], src, n);
1733			break;
1734
1735		case 'S':	/* scroll up n lines */
1736			n = scp->term.param[0]; if (n < 1)  n = 1;
1737			if (n > scp->ypos)
1738				n = scp->ypos;
1739			bcopy(scp->crt_base + (scp->xsize * n),
1740			      scp->crt_base,
1741			      scp->xsize * (scp->ysize - n) *
1742			      sizeof(u_short));
1743			fillw(scp->term.cur_attr | scr_map[0x20],
1744			      scp->crt_base + scp->xsize *
1745			      (scp->ysize - 1),
1746			      scp->xsize);
1747			break;
1748
1749		case 'T':	/* scroll down n lines */
1750			n = scp->term.param[0]; if (n < 1)  n = 1;
1751			if (n > scp->ysize - scp->ypos)
1752				n = scp->ysize - scp->ypos;
1753			bcopy(scp->crt_base,
1754			      scp->crt_base + (scp->xsize * n),
1755			      scp->xsize * (scp->ysize - n) *
1756			      sizeof(u_short));
1757			fillw(scp->term.cur_attr | scr_map[0x20],
1758			      scp->crt_base, scp->xsize);
1759			break;
1760
1761		case 'X':	/* delete n characters in line */
1762			n = scp->term.param[0]; if (n < 1)  n = 1;
1763			if (n > scp->xsize - scp->xpos)
1764				n = scp->xsize - scp->xpos;
1765			fillw(scp->term.cur_attr | scr_map[0x20],
1766                              scp->crt_base + scp->xpos +
1767			      ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
1768			break;
1769
1770		case 'Z':	/* move n tabs backwards */
1771			n = scp->term.param[0]; if (n < 1)  n = 1;
1772			if ((i = scp->xpos & 0xf8) == scp->xpos)
1773				i -= 8*n;
1774			else
1775				i -= 8*(n-1);
1776			if (i < 0)
1777				i = 0;
1778			move_crsr(scp, i, scp->ypos);
1779			break;
1780
1781		case '`': 	/* move cursor to column n */
1782			n = scp->term.param[0]; if (n < 1)  n = 1;
1783			move_crsr(scp, n, scp->ypos);
1784			break;
1785
1786		case 'a': 	/* move cursor n columns to the right */
1787			n = scp->term.param[0]; if (n < 1)  n = 1;
1788			move_crsr(scp, scp->xpos + n, scp->ypos);
1789			break;
1790
1791		case 'd': 	/* move cursor to row n */
1792			n = scp->term.param[0]; if (n < 1)  n = 1;
1793			move_crsr(scp, scp->xpos, n);
1794			break;
1795
1796		case 'e': 	/* move cursor n rows down */
1797			n = scp->term.param[0]; if (n < 1)  n = 1;
1798			move_crsr(scp, scp->xpos, scp->ypos + n);
1799			break;
1800
1801		case 'm': 	/* change attribute */
1802			if (scp->term.num_param == 0) {
1803				scp->term.cur_attr = scp->term.std_attr;
1804				break;
1805			}
1806			for (i = 0; i < scp->term.num_param; i++) {
1807				switch (n = scp->term.param[i]) {
1808				case 0:	/* back to normal */
1809					scp->term.cur_attr = scp->term.std_attr;
1810					break;
1811				case 1:	/* highlight (bold) */
1812					scp->term.cur_attr &= 0xFF00;
1813					scp->term.cur_attr |= 0x0800;
1814					break;
1815				case 4: /* highlight (underline) */
1816					scp->term.cur_attr &= 0xFF00;
1817					scp->term.cur_attr |= 0x0800;
1818					break;
1819				case 5: /* blink */
1820					scp->term.cur_attr &= 0xFF00;
1821					scp->term.cur_attr |= 0x8000;
1822					break;
1823				case 7: /* reverse video */
1824					scp->term.cur_attr = scp->term.rev_attr;
1825					break;
1826				case 30: case 31: /* set fg color */
1827				case 32: case 33: case 34:
1828				case 35: case 36: case 37:
1829					scp->term.cur_attr =
1830						(scp->term.cur_attr & 0xF8FF)
1831						| (ansi_col[(n-30) & 7] << 8);
1832					break;
1833				case 40: case 41: /* set bg color */
1834				case 42: case 43: case 44:
1835				case 45: case 46: case 47:
1836					scp->term.cur_attr =
1837						(scp->term.cur_attr & 0x8FFF)
1838						| (ansi_col[(n-40) & 7] << 12);
1839					break;
1840				}
1841			}
1842			break;
1843
1844		case 'x':
1845			if (scp->term.num_param == 0)
1846				n = 0;
1847			else
1848				n = scp->term.param[0];
1849			switch (n) {
1850			case 0: 	/* reset attributes */
1851				scp->term.cur_attr = scp->term.std_attr =
1852					current_default->std_attr;
1853				scp->term.rev_attr = current_default->rev_attr;
1854				break;
1855			case 1: 	/* set ansi background */
1856				scp->term.cur_attr = scp->term.std_attr =
1857					(scp->term.std_attr & 0x0F00) |
1858					(ansi_col[(scp->term.param[1])&0x0F]<<12);
1859				break;
1860			case 2: 	/* set ansi foreground */
1861				scp->term.cur_attr = scp->term.std_attr =
1862					(scp->term.std_attr & 0xF000) |
1863					(ansi_col[(scp->term.param[1])&0x0F]<<8);
1864				break;
1865			case 3: 	/* set ansi attribute directly */
1866				scp->term.cur_attr = scp->term.std_attr =
1867					(scp->term.param[1]&0xFF)<<8;
1868				break;
1869			case 5: 	/* set ansi reverse video background */
1870				scp->term.rev_attr =
1871					(scp->term.rev_attr & 0x0F00) |
1872					(ansi_col[(scp->term.param[1])&0x0F]<<12);
1873				break;
1874			case 6: 	/* set ansi reverse video foreground */
1875				scp->term.rev_attr =
1876					(scp->term.rev_attr & 0xF000) |
1877					(ansi_col[(scp->term.param[1])&0x0F]<<8);
1878				break;
1879			case 7: 	/* set ansi reverse video directly */
1880				scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
1881				break;
1882			}
1883			break;
1884
1885		case 'z':	/* switch to (virtual) console n */
1886			if (scp->term.num_param == 1)
1887				switch_scr(scp->term.param[0]);
1888			break;
1889		}
1890	}
1891	else if (scp->term.esc == 3) {
1892		if (c >= '0' && c <= '9') {
1893			if (scp->term.num_param < MAX_ESC_PAR) {
1894				if (scp->term.last_param != scp->term.num_param) {
1895					scp->term.last_param = scp->term.num_param;
1896					scp->term.param[scp->term.num_param] = 0;
1897				}
1898				else
1899					scp->term.param[scp->term.num_param] *= 10;
1900				scp->term.param[scp->term.num_param] += c - '0';
1901				return;
1902			}
1903		}
1904		scp->term.num_param = scp->term.last_param + 1;
1905		switch (c) {
1906
1907		case ';':
1908			if (scp->term.num_param < MAX_ESC_PAR)
1909				return;
1910			break;
1911
1912		case 'A':	/* set display border color */
1913			if (scp->term.num_param == 1)
1914				scp->border=scp->term.param[0] & 0xff;
1915				if (scp == cur_console)
1916					set_border(scp->border);
1917			break;
1918
1919		case 'B':	/* set bell pitch and duration */
1920			if (scp->term.num_param == 2) {
1921				scp->bell_pitch = scp->term.param[0];
1922				scp->bell_duration = scp->term.param[1]*10;
1923			}
1924			break;
1925
1926		case 'C': 	/* set cursor shape (start & end line) */
1927			if (scp->term.num_param == 2) {
1928				scp->cursor_start = scp->term.param[0] & 0x1F;
1929				scp->cursor_end = scp->term.param[1] & 0x1F;
1930				if (scp == cur_console)
1931					cursor_shape(scp->cursor_start,
1932						     scp->cursor_end);
1933			}
1934			break;
1935
1936		case 'F':	/* set ansi foreground */
1937			if (scp->term.num_param == 1)
1938				scp->term.cur_attr = scp->term.std_attr =
1939					(scp->term.std_attr & 0xF000)
1940					| ((scp->term.param[0] & 0x0F) << 8);
1941			break;
1942
1943		case 'G': 	/* set ansi background */
1944			if (scp->term.num_param == 1)
1945				scp->term.cur_attr = scp->term.std_attr =
1946					(scp->term.std_attr & 0x0F00)
1947					| ((scp->term.param[0] & 0x0F) << 12);
1948			break;
1949
1950		case 'H':	/* set ansi reverse video foreground */
1951			if (scp->term.num_param == 1)
1952				scp->term.rev_attr =
1953					(scp->term.rev_attr & 0xF000)
1954					| ((scp->term.param[0] & 0x0F) << 8);
1955			break;
1956
1957		case 'I': 	/* set ansi reverse video background */
1958			if (scp->term.num_param == 1)
1959				scp->term.rev_attr =
1960					(scp->term.rev_attr & 0x0F00)
1961					| ((scp->term.param[0] & 0x0F) << 12);
1962			break;
1963		}
1964	}
1965	scp->term.esc = 0;
1966}
1967
1968static void
1969ansi_put(scr_stat *scp, u_char c)
1970{
1971	if (scp->status & UNKNOWN_MODE)
1972		return;
1973
1974	/* make screensaver happy */
1975	if (scp == cur_console) {
1976		scrn_time_stamp = time.tv_sec;
1977		if (scrn_blanked)
1978			SCRN_SAVER(0);
1979	}
1980	in_putc++;
1981	if (scp->term.esc)
1982		scan_esc(scp, c);
1983	else switch(c) {
1984	case 0x1B:	/* start escape sequence */
1985		scp->term.esc = 1;
1986		scp->term.num_param = 0;
1987		break;
1988	case 0x07:
1989		if (scp == cur_console)
1990		 	sysbeep(scp->bell_pitch, scp->bell_duration);
1991		break;
1992	case '\t':	/* non-destructive tab */
1993		scp->crtat += (8 - scp->xpos % 8);
1994		scp->xpos += (8 - scp->xpos % 8);
1995		break;
1996	case '\b':      /* non-destructive backspace */
1997		if (scp->crtat > scp->crt_base) {
1998			scp->crtat--;
1999			if (scp->xpos > 0)
2000				scp->xpos--;
2001			else {
2002				scp->xpos += scp->xsize - 1;
2003				scp->ypos--;
2004			}
2005		}
2006		break;
2007	case '\r':	/* return to pos 0 */
2008		move_crsr(scp, 0, scp->ypos);
2009		break;
2010	case '\n':	/* newline, same pos */
2011		scp->crtat += scp->xsize;
2012		scp->ypos++;
2013		break;
2014	case '\f':	/* form feed, clears screen */
2015		clear_screen(scp);
2016		break;
2017	default:
2018		/* Print only printables */
2019		*scp->crtat = (scp->term.cur_attr | scr_map[c]);
2020		scp->crtat++;
2021		if (++scp->xpos >= scp->xsize) {
2022			scp->xpos = 0;
2023			scp->ypos++;
2024		}
2025		break;
2026	}
2027	if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
2028		bcopy(scp->crt_base + scp->xsize, scp->crt_base,
2029			scp->xsize * (scp->ysize - 1) * sizeof(u_short));
2030		fillw(scp->term.cur_attr | scr_map[0x20],
2031			scp->crt_base + scp->xsize * (scp->ysize - 1),
2032			scp->xsize);
2033		scp->crtat -= scp->xsize;
2034		scp->ypos--;
2035	}
2036	in_putc--;
2037	if (delayed_next_scr)
2038		switch_scr(delayed_next_scr - 1);
2039}
2040
2041static void
2042scinit(void)
2043{
2044	u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
2045	unsigned cursorat;
2046	int start = -1, end = -1, i;
2047	scr_stat *scp;
2048
2049	/*
2050	 * catch that once in a blue moon occurence when scinit is called
2051	 * TWICE, adding the CGA_BUF offset again -> poooff
2052	 */
2053	if (crtat != 0)
2054		return;
2055	/*
2056	 * Crtat initialized to point to MONO buffer, if not present change
2057	 * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
2058	 * in the remapped offset at the "right" time
2059	 */
2060	was = *cp;
2061	*cp = (u_short) 0xA55A;
2062	if (*cp != 0xA55A) {
2063		crtc_addr = MONO_BASE;
2064		color_display =	0;
2065	} else {
2066		*cp = was;
2067		crtc_addr = COLOR_BASE;
2068		Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
2069		color_display =	1;
2070	}
2071
2072	/* Extract cursor location */
2073	outb(crtc_addr,14);
2074	cursorat = inb(crtc_addr+1)<<8 ;
2075	outb(crtc_addr,15);
2076	cursorat |= inb(crtc_addr+1);
2077	crtat = Crtat + cursorat;
2078
2079	/* is this a VGA or higher ? */
2080	outb(crtc_addr, 7);
2081	if (inb(crtc_addr) == 7) {
2082		crtc_vga = 1;
2083#if defined(FAT_CURSOR)
2084                start = 0;
2085                end = 18;
2086		cursor_shape(start, end);
2087#else
2088		get_cursor_shape(&start, &end);
2089#endif
2090	}
2091	current_default = &user_default;
2092	for (i = 0; i < NCONS; i++) {
2093		scp = &console[i];
2094		scp->mode = M_VGA_C80x25;
2095		scp->term.esc = 0;
2096		scp->term.std_attr = current_default->std_attr;
2097		scp->term.rev_attr = current_default->rev_attr;
2098		scp->term.cur_attr = scp->term.std_attr;
2099		scp->border = BG_BLACK;
2100		scp->cursor_start = start;
2101		scp->cursor_end = end;
2102		scp->xsize = COL;
2103		scp->ysize = ROW;
2104		scp->bell_pitch = BELL_PITCH;
2105		scp->bell_duration = BELL_DURATION;
2106#ifndef LAPTOP
2107		scp->status = NLKED;
2108#else
2109		scp->status = 0;
2110#endif
2111		scp->pid = 0;
2112		scp->proc = NULL;
2113		scp->smode.mode = VT_AUTO;
2114		if (i == 0) {
2115			scp->xpos = cursorat % COL;
2116			scp->ypos = cursorat / COL;
2117			scp->crt_base = Crtat;
2118			scp->crtat = crtat;
2119		}
2120	}
2121	kernel_console.esc = 0;
2122	kernel_console.std_attr = kernel_default.std_attr;
2123	kernel_console.rev_attr = kernel_default.rev_attr;
2124	kernel_console.cur_attr = kernel_default.std_attr;
2125	/* initialize mapscrn array to a one to one map */
2126	for (i=0; i<sizeof(scr_map); i++)
2127		scr_map[i] = i;
2128}
2129
2130static void
2131scput(u_char c)
2132{
2133	scr_stat *scp = &console[0];
2134	term_stat save;
2135
2136	if (crtat == 0)
2137		scinit();
2138	if( in_putc == 0) {
2139		++in_putc;
2140		save = scp->term;
2141		scp->term = kernel_console;
2142		current_default = &kernel_default;
2143		ansi_put(scp, c);
2144		kernel_console = scp->term;
2145		current_default = &user_default;
2146		scp->term = save;
2147		--in_putc;
2148	} else {
2149		if( console_buffer_count < CONSOLE_BUFSIZE)
2150			console_buffer[console_buffer_count++] = c;
2151	}
2152}
2153
2154static u_char
2155*get_fstr(u_int c, u_int *len)
2156{
2157	u_int i;
2158
2159	if (!(c & FKEY))
2160		return(NULL);
2161	i = (c & 0xFF) - F_FN;
2162	if (i > n_fkey_tab)
2163		return(NULL);
2164	*len = fkey_tab[i].len;
2165	return(fkey_tab[i].str);
2166}
2167
2168static void
2169update_leds(int which)
2170{
2171	int s;
2172  	static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2173
2174	/* replace CAPS led with ALTGR led for ALTGR keyboards */
2175	if (key_map.n_keys > ALTGR_OFFSET) {
2176		if (which & ALKED)
2177			which |= CLKED;
2178		else
2179			which &= ~CLKED;
2180	}
2181	s = spltty();
2182	kbd_cmd(KB_SETLEDS);
2183	kbd_cmd(xlate_leds[which & LED_MASK]);
2184	splx(s);
2185}
2186
2187/*
2188 * scgetc(noblock) - get character from keyboard.
2189 * If noblock = 0 wait until a key is pressed.
2190 * Else return NOKEY.
2191 */
2192u_int
2193scgetc(int noblock)
2194{
2195	u_char scancode, keycode;
2196	u_int state, action;
2197	struct key_t *key;
2198	static u_char esc_flag = 0, compose = 0;
2199	static u_int chr = 0;
2200
2201next_code:
2202	kbd_wait();
2203	/* First see if there is something in the keyboard port */
2204	if (inb(KB_STAT) & KB_BUF_FULL)
2205		scancode = inb(KB_DATA);
2206	else if (noblock)
2207		return(NOKEY);
2208	else
2209		goto next_code;
2210
2211	if (cur_console->status & KBD_RAW_MODE)
2212		return scancode;
2213#if ASYNCH
2214	if (scancode == KB_ACK || scancode == KB_RESEND) {
2215		kbd_reply = scancode;
2216		if (noblock)
2217			return(NOKEY);
2218		goto next_code;
2219	}
2220#endif
2221	keycode = scancode & 0x7F;
2222	switch (esc_flag) {
2223	case 0x00:		/* normal scancode */
2224		switch(scancode) {
2225		case 0xB8:	/* left alt  (compose key) */
2226			if (compose) {
2227				compose = 0;
2228				if (chr > 255) {
2229					sysbeep(BELL_PITCH, BELL_DURATION);
2230					chr = 0;
2231				}
2232			}
2233			break;
2234		case 0x38:
2235			if (!compose) {
2236				compose = 1;
2237				chr = 0;
2238			}
2239			break;
2240		case 0xE0:
2241		case 0xE1:
2242			esc_flag = scancode;
2243			goto next_code;
2244		}
2245		break;
2246	case 0xE0:		/* 0xE0 prefix */
2247		esc_flag = 0;
2248		switch (keycode) {
2249		case 0x1C:	/* right enter key */
2250			keycode = 0x59;
2251			break;
2252		case 0x1D:	/* right ctrl key */
2253			keycode = 0x5A;
2254			break;
2255		case 0x35:	/* keypad divide key */
2256			keycode = 0x5B;
2257			break;
2258		case 0x37:	/* print scrn key */
2259			keycode = 0x5C;
2260			break;
2261		case 0x38:	/* right alt key (alt gr) */
2262			keycode = 0x5D;
2263			break;
2264		case 0x47:	/* grey home key */
2265			keycode = 0x5E;
2266			break;
2267		case 0x48:	/* grey up arrow key */
2268			keycode = 0x5F;
2269			break;
2270		case 0x49:	/* grey page up key */
2271			keycode = 0x60;
2272			break;
2273		case 0x4B:	/* grey left arrow key */
2274			keycode = 0x61;
2275			break;
2276		case 0x4D:	/* grey right arrow key */
2277			keycode = 0x62;
2278			break;
2279		case 0x4F:	/* grey end key */
2280			keycode = 0x63;
2281			break;
2282		case 0x50:	/* grey down arrow key */
2283			keycode = 0x64;
2284			break;
2285		case 0x51:	/* grey page down key */
2286			keycode = 0x65;
2287			break;
2288		case 0x52:	/* grey insert key */
2289			keycode = 0x66;
2290			break;
2291		case 0x53:	/* grey delete key */
2292			keycode = 0x67;
2293			break;
2294		default:	/* ignore everything else */
2295			goto next_code;
2296		}
2297		break;
2298	case 0xE1:		/* 0xE1 prefix */
2299		esc_flag = 0;
2300		if (keycode == 0x1D)
2301			esc_flag = 0x1D;
2302		goto next_code;
2303		/* NOT REACHED */
2304	case 0x1D:		/* pause / break */
2305		esc_flag = 0;
2306		if (keycode != 0x45)
2307			goto next_code;
2308		keycode = 0x68;
2309		break;
2310	}
2311
2312	if (compose) {
2313		switch (scancode) {
2314		/* key pressed process it */
2315		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
2316			chr = (scancode - 0x40) + chr*10;
2317			goto next_code;
2318		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
2319			chr = (scancode - 0x47) + chr*10;
2320			goto next_code;
2321		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
2322			chr = (scancode - 0x4E) + chr*10;
2323			goto next_code;
2324		case 0x52:				/* keypad 0 */
2325			chr *= 10;
2326			goto next_code;
2327
2328		/* key release, no interest here */
2329		case 0xC7: case 0xC8: case 0xC9:	/* keypad 7,8,9 */
2330		case 0xCB: case 0xCC: case 0xCD:	/* keypad 4,5,6 */
2331		case 0xCF: case 0xD0: case 0xD1:	/* keypad 1,2,3 */
2332		case 0xD2:				/* keypad 0 */
2333			goto next_code;
2334
2335		case 0x38:				/* left alt key */
2336			break;
2337		default:
2338			if (chr) {
2339				compose = chr = 0;
2340				sysbeep(BELL_PITCH, BELL_DURATION);
2341				goto next_code;
2342			}
2343			break;
2344		}
2345	}
2346
2347	state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
2348	if ((!agrs && (cur_console->status & ALKED))
2349	    || (agrs && !(cur_console->status & ALKED)))
2350		keycode += ALTGR_OFFSET;
2351	key = &key_map.key[keycode];
2352	if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
2353	     || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
2354		state ^= 1;
2355
2356	/* Check for make/break */
2357	action = key->map[state];
2358	if (scancode & 0x80) { 		/* key released */
2359		if (key->spcl & 0x80) {
2360			switch (action) {
2361			case LSH:
2362				shfts &= ~1;
2363				break;
2364			case RSH:
2365				shfts &= ~2;
2366				break;
2367			case LCTR:
2368				ctls &= ~1;
2369				break;
2370			case RCTR:
2371				ctls &= ~2;
2372				break;
2373			case LALT:
2374				alts &= ~1;
2375				break;
2376			case RALT:
2377				alts &= ~2;
2378				break;
2379			case NLK:
2380				nlkcnt = 0;
2381				break;
2382			case CLK:
2383				clkcnt = 0;
2384				break;
2385			case SLK:
2386				slkcnt = 0;
2387				break;
2388			case ASH:
2389				agrs = 0;
2390				break;
2391			case ALK:
2392				alkcnt = 0;
2393				break;
2394			case META:
2395				metas = 0;
2396				break;
2397			}
2398		}
2399		if (chr && !compose) {
2400			action = chr;
2401			chr = 0;
2402			return(action);
2403		}
2404	} else {
2405		/* key pressed */
2406		if (key->spcl & (0x80>>state)) {
2407			switch (action) {
2408			/* LOCKING KEYS */
2409			case NLK:
2410				if (!nlkcnt) {
2411					nlkcnt++;
2412					if (cur_console->status & NLKED)
2413						cur_console->status &= ~NLKED;
2414					else
2415						cur_console->status |= NLKED;
2416					update_leds(cur_console->status);
2417				}
2418				break;
2419			case CLK:
2420				if (!clkcnt) {
2421					clkcnt++;
2422					if (cur_console->status & CLKED)
2423						cur_console->status &= ~CLKED;
2424					else
2425						cur_console->status |= CLKED;
2426					update_leds(cur_console->status);
2427				}
2428				break;
2429			case SLK:
2430				if (!slkcnt) {
2431					slkcnt++;
2432					if (cur_console->status & SLKED) {
2433						cur_console->status &= ~SLKED;
2434						pcstart(VIRTUAL_TTY(get_scr_num()));
2435					}
2436					else
2437						cur_console->status |= SLKED;
2438					update_leds(cur_console->status);
2439				}
2440				break;
2441 			case ALK:
2442				if (!alkcnt) {
2443					alkcnt++;
2444 					if (cur_console->status & ALKED)
2445 						cur_console->status &= ~ALKED;
2446 					else
2447 						cur_console->status |= ALKED;
2448					update_leds(cur_console->status);
2449				}
2450  				break;
2451
2452			/* NON-LOCKING KEYS */
2453			case NOP:
2454				break;
2455			case RBT:
2456				shutdown_nice();
2457				break;
2458			case SUSP:
2459				break;
2460
2461			case DBG:
2462#ifdef DDB			/* try to switch to console 0 */
2463				if (cur_console->smode.mode == VT_AUTO &&
2464		    		    console[0].smode.mode == VT_AUTO)
2465					switch_scr(0);
2466				Debugger("manual escape to debugger");
2467				return(NOKEY);
2468#else
2469				printf("No debugger in kernel\n");
2470#endif
2471				break;
2472			case LSH:
2473				shfts |= 1;
2474				break;
2475			case RSH:
2476				shfts |= 2;
2477				break;
2478			case LCTR:
2479				ctls |= 1;
2480				break;
2481			case RCTR:
2482				ctls |= 2;
2483				break;
2484			case LALT:
2485				alts |= 1;
2486				break;
2487			case RALT:
2488				alts |= 2;
2489				break;
2490			case ASH:
2491				agrs = 1;
2492				break;
2493			case META:
2494				metas = 1;
2495				break;
2496			case NEXT:
2497				switch_scr((get_scr_num()+1)%NCONS);
2498				break;
2499			default:
2500				if (action >= F_SCR && action <= L_SCR) {
2501					switch_scr(action - F_SCR);
2502					break;
2503				}
2504				if (action >= F_FN && action <= L_FN)
2505					action |= FKEY;
2506				return(action);
2507			}
2508		}
2509		else {
2510			if (metas)
2511				action |= MKEY;
2512 			return(action);
2513		}
2514	}
2515	goto next_code;
2516}
2517
2518int
2519getchar(void)
2520{
2521	u_char thechar;
2522	int s;
2523
2524	polling = 1;
2525	s = splhigh();
2526	scput('>');
2527	thechar = (u_char) scgetc(0);
2528	polling = 0;
2529	splx(s);
2530	switch (thechar) {
2531	default:
2532		if (thechar >= scr_map[0x20])
2533			scput(thechar);
2534		return(thechar);
2535	case cr:
2536	case lf:
2537		scput(cr); scput(lf);
2538		return(lf);
2539	case bs:
2540	case del:
2541		scput(bs); scput(scr_map[0x20]); scput(bs);
2542		return(thechar);
2543	case cntld:
2544		scput('^'); scput('D'); scput('\r'); scput('\n');
2545		return(0);
2546	}
2547}
2548
2549u_int
2550sgetc(int noblock)
2551{
2552	return (scgetc(noblock) & 0xff);
2553}
2554
2555int
2556pcmmap(dev_t dev, int offset, int nprot)
2557{
2558	if (offset > 0x20000)
2559		return EINVAL;
2560	return i386_btop((VIDEOMEM + offset));
2561}
2562
2563static void
2564kbd_wait(void)
2565{
2566	int i = 1000;
2567
2568	while (i--) {
2569		if ((inb(KB_STAT) & KB_READY) == 0)
2570			break;
2571		DELAY (10);
2572	}
2573}
2574
2575static void
2576kbd_cmd(u_char command)
2577{
2578	int retry = 5;
2579	do {
2580		int i = 100000;
2581
2582		kbd_wait();
2583#if ASYNCH
2584		kbd_reply = 0;
2585		outb(KB_DATA, command);
2586		while (i--) {
2587			if (kbd_reply == KB_ACK)
2588				return;
2589			if (kbd_reply == KB_RESEND)
2590				break;
2591		}
2592#else
2593		outb(KB_DATA, command);
2594		while (i--) {
2595			if (inb(KB_STAT) & KB_BUF_FULL) {
2596				int val;
2597				DELAY(10);
2598				val = inb(KB_DATA);
2599				if (val == KB_ACK)
2600					return;
2601				if (val == KB_RESEND)
2602					break;
2603			}
2604		}
2605#endif
2606	} while (retry--);
2607}
2608
2609static void
2610set_mode(scr_stat *scp)
2611{
2612	char *modetable;
2613	char special_modetable[64];
2614	int mode, font_size;
2615
2616	if (scp != cur_console)
2617		return;
2618
2619	/* mode change only on VGA's */
2620	if (!crtc_vga) {
2621		/* (re)activate cursor */
2622		untimeout((timeout_t)cursor_pos, 0);
2623		cursor_pos(1);
2624		return;
2625	}
2626
2627	/* setup video hardware for the given mode */
2628	switch (scp->mode) {
2629       	case M_VGA_C80x50:
2630		bcopy(video_mode_ptr+(64*M_VGA_C80x25), &special_modetable, 64);
2631		special_modetable[2] = 8;
2632		special_modetable[19] = 7;
2633		modetable = special_modetable;
2634		goto setup_mode;
2635
2636	case M_VGA_M80x50:
2637		bcopy(video_mode_ptr+(64*M_VGA_M80x25), &special_modetable, 64);
2638		special_modetable[2] = 8;
2639		special_modetable[19] = 7;
2640		modetable = special_modetable;
2641		goto setup_mode;
2642
2643       	case M_ENH_B80x43:
2644		bcopy(video_mode_ptr+(64*M_ENH_B80x25), &special_modetable, 64);
2645		special_modetable[2] = 8;
2646		special_modetable[19] = 7;
2647		special_modetable[28] = 87;
2648		modetable = special_modetable;
2649		goto setup_mode;
2650
2651	case M_ENH_C80x43:
2652		bcopy(video_mode_ptr+(64*M_ENH_C80x25), &special_modetable, 64);
2653		special_modetable[2] = 8;
2654		special_modetable[19] = 7;
2655		special_modetable[28] = 87;
2656		modetable = special_modetable;
2657		goto setup_mode;
2658
2659       	case M_VGA_C40x25: case M_VGA_C80x25:	/* VGA TEXT MODES */
2660	case M_VGA_M80x25:
2661       	case M_B40x25:     case M_C40x25:
2662       	case M_B80x25:     case M_C80x25:
2663       	case M_ENH_B40x25: case M_ENH_C40x25:
2664       	case M_ENH_B80x25: case M_ENH_C80x25:
2665
2666		modetable = (char*)(video_mode_ptr + (scp->mode * 64));
2667setup_mode:
2668		set_vgaregs(modetable);
2669		font_size = *(modetable + 2);
2670		/* change cursor type if set */
2671		if (scp->cursor_start != -1 && scp->cursor_end != -1)
2672			cursor_shape(
2673			(scp->cursor_start >= font_size)
2674			? font_size - 1
2675			: scp->cursor_start,
2676			(scp->cursor_end >= font_size)
2677			? font_size - 1
2678			: scp->cursor_end);
2679
2680		/* set font type (size) */
2681 		switch (font_size) {
2682 		case 0x08:
2683 	    		outb(TSIDX, 0x03); outb(TSREG, 0x05);	/* font 1 */
2684 			break;
2685 		case 0x0E:
2686 	    		outb(TSIDX, 0x03); outb(TSREG, 0x0A);	/* font 2 */
2687 			break;
2688 		case 0x10:
2689 	    		outb(TSIDX, 0x03); outb(TSREG, 0x00);	/* font 0 */
2690 			break;
2691 		default:
2692 	    		outb(TSIDX, 0x03); outb(TSREG, 0x05);	/* font 1 */
2693 		}
2694
2695 		/* (re)activate cursor */
2696 		untimeout((timeout_t)cursor_pos, 0);
2697 		cursor_pos(1);
2698		break;
2699
2700	case M_BG320:      case M_CG320:      case M_BG640:
2701	case M_CG320_D:    case M_CG640_E:
2702	case M_CG640x350:  case M_ENH_CG640:
2703	case M_BG640x480:  case M_CG640x480:  case M_VGA_CG320:
2704
2705 		set_vgaregs(video_mode_ptr + (scp->mode * 64));
2706		break;
2707
2708	default:
2709		/* call user defined function XXX */
2710		break;
2711	}
2712
2713	/* set border color for this (virtual) console */
2714	set_border(scp->border);
2715	return;
2716}
2717
2718static void
2719set_border(int color)
2720{
2721	inb(crtc_addr+6); 				/* reset flip-flop */
2722	outb(ATC, 0x11); outb(ATC, color);
2723 	inb(crtc_addr+6); 				/* reset flip-flop */
2724 	outb(ATC, 0x20);				/* enable Palette */
2725}
2726
2727static void
2728set_vgaregs(char *modetable)
2729{
2730	int i, s = splhigh();
2731
2732	outb(TSIDX, 0x00); outb(TSREG, 0x01);	/* stop sequencer */
2733	outb(TSIDX, 0x07); outb(TSREG, 0x00);	/* unlock registers */
2734	for (i=0; i<4; i++) {			/* program sequencer */
2735		outb(TSIDX, i+1);
2736		outb(TSREG, modetable[i+5]);
2737	}
2738	outb(MISC, modetable[9]);		/* set dot-clock */
2739	outb(TSIDX, 0x00); outb(TSREG, 0x03);	/* start sequencer */
2740	outb(crtc_addr, 0x11);
2741	outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
2742	for (i=0; i<25; i++) {			/* program crtc */
2743		outb(crtc_addr, i);
2744		outb(crtc_addr+1, modetable[i+10]);
2745	}
2746	inb(crtc_addr+6); 			/* reset flip-flop */
2747	for (i=0; i<20; i++) {			/* program attribute ctrl */
2748		outb(ATC, i);
2749		outb(ATC, modetable[i+35]);
2750	}
2751	for (i=0; i<9; i++) {			/* program graph data ctrl */
2752		outb(GDCIDX, i);
2753		outb(GDCREG, modetable[i+55]);
2754	}
2755	inb(crtc_addr+6); 			/* reset flip-flop */
2756	outb(ATC ,0x20);			/* enable palette */
2757	splx(s);
2758}
2759
2760static void
2761copy_font(int direction, int segment, int size, char* font)
2762{
2763  	int ch, line, s;
2764	u_char val;
2765
2766 	outb(TSIDX, 0x01); val = inb(TSREG); 		/* blank screen */
2767	outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
2768
2769	/* setup vga for loading fonts (graphics plane mode) */
2770	inb(crtc_addr+6);				/* reset flip/flop */
2771	outb(ATC, 0x30); outb(ATC, 0x01);
2772	outb(TSIDX, 0x02); outb(TSREG, 0x04);
2773	outb(TSIDX, 0x04); outb(TSREG, 0x06);
2774	outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
2775	outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
2776	outb(GDCIDX, 0x06); outb(GDCREG, 0x05);		/* addr = a0000, 64kb */
2777    	for (ch=0; ch < 256; ch++)
2778	    for (line=0; line < size; line++)
2779		if (direction)
2780		    *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
2781					font[(ch*size)+line];
2782		else
2783		    font[(ch*size)+line] =
2784		    *((char *)atdevbase+(segment*0x4000)+(ch*32)+line);
2785	/* setup vga for text mode again */
2786	s = splhigh();
2787	inb(crtc_addr+6);				/* reset flip/flop */
2788	outb(ATC, 0x30); outb(ATC, 0x0C);
2789	outb(TSIDX, 0x02); outb(TSREG, 0x03);
2790	outb(TSIDX, 0x04); outb(TSREG, 0x02);
2791	outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
2792	outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
2793	if (crtc_addr == MONO_BASE) {
2794		outb(GDCIDX, 0x06); outb(GDCREG, 0x0A);	/* addr = b0000, 32kb */
2795	}
2796	else {
2797		outb(GDCIDX, 0x06); outb(GDCREG, 0x0E);	/* addr = b8000, 32kb */
2798	}
2799	splx(s);
2800 	outb(TSIDX, 0x01); val = inb(TSREG); 		/* unblank screen */
2801	outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
2802}
2803
2804static void
2805load_palette(void)
2806{
2807	int i;
2808
2809  	outb(PIXMASK, 0xFF);			/* no pixelmask */
2810  	outb(PALWADR, 0x00);
2811  	for (i=0x00; i<0x300; i++)
2812    		 outb(PALDATA, palette[i]);
2813	inb(crtc_addr+6);			/* reset flip/flop */
2814	outb(ATC, 0x20);			/* enable palette */
2815}
2816
2817static void
2818save_palette(void)
2819{
2820	int i;
2821
2822  	outb(PALRADR, 0x00);
2823  	for (i=0x00; i<0x300; i++)
2824    		palette[i] = inb(PALDATA);
2825	inb(crtc_addr+6);			/* reset flip/flop */
2826}
2827
2828#endif /* NSC */
2829