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