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