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