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