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