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