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