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