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