/*
 * Copyright (c) 1992, 1995 Hellmuth Michaelis and Joerg Wunsch.
 *
 * Copyright (c) 1992, 1993 Brian Dunford-Shore.
 *
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz and Don Ahn.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Hellmuth Michaelis,
 *	Brian Dunford-Shore and Joerg Wunsch.
 * 4. The name authors may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @(#)pcvt_out.c, 3.20, Last Edit-Date: [Sun Apr  2 18:59:11 1995]
 *
 */

/*---------------------------------------------------------------------------*
 *
 *	pcvt_out.c	VT220 Terminal Emulator
 *	---------------------------------------
 *	-hm	------------ Release 3.00 --------------
 *	-hm	integrating NetBSD-current patches
 *	-hm	integrating patch from Thomas Gellekum
 *	-hm	bugfix: clear last line when hpmode 28lines and force 24
 *	-hm	right fkey labels after soft/hard reset
 *	-hm	patch from Joerg for comconsole operation
 *	-hm	patch from Lon Willet to preserve the initial cursor shape
 *	-hm	if FAT_CURSOR is defined, you get the old cursor type back ..
 *	-hm	patch from Lon Willett regarding winsize settings
 *	-hm	applying patch from Joerg fixing Crtat bug, non VGA startup bug
 *	-hm	setting variable color for CGA and MDA/HGC in coldinit
 *	-hm	fixing bug initializing cursor position on startup
 *	-hm	fixing support for EGA boards in vt_coldinit()
 *
 *---------------------------------------------------------------------------*/

#include "vt.h"
#if NVT > 0

#define PCVT_INCLUDE_VT_SELATTR	/* get inline function from pcvt_hdr.h */

#include <i386/isa/pcvt/pcvt_hdr.h>	/* global include */
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>

extern u_short csd_ascii[];	/* pcvt_tbl.h */
extern u_short csd_supplemental[];

static void write_char (struct video_state *svsp, int attrib, int ch);
static void check_scroll ( struct video_state *svsp );
static void hp_entry ( U_char ch, struct video_state *svsp );
static void vt_coldinit ( void );
static void wrfkl ( int num, u_char *string, struct video_state *svsp );
static void writefkl ( int num, u_char *string, struct video_state *svsp );


/*---------------------------------------------------------------------------*
 *	do character set transformation and write to display memory (inline)
 *---------------------------------------------------------------------------*/

#define video (svsp->Crtat + svsp->cur_offset)

static __inline void write_char (svsp, attrib, ch)
struct	video_state *svsp;
u_short	attrib, ch;		/* XXX inefficient interface */
{
	if ((ch >= 0x20) && (ch <= 0x7f))	/* use GL if ch >= 0x20 */
	{
		if(!svsp->ss)		/* single shift G2/G3 -> GL ? */
		{
			*video = attrib | (*svsp->GL)[ch-0x20];
		}
		else
		{
			*video = attrib | (*svsp->Gs)[ch-0x20];
			svsp->ss = 0;
		}
	}
	else
	{
		svsp->ss = 0;

		if(ch >= 0x80)			/* display controls C1 */
		{
			if(ch >= 0xA0)		/* use GR if ch >= 0xA0 */
			{
				*video = attrib | (*svsp->GR)[ch-0xA0];
			}
			else
			{
				if(vgacs[svsp->vga_charset].secondloaded)
				{
					*video = attrib | ((ch-0x60) | CSH);
				}
				else	/* use normal ibm charset for
							control display */
				{
					*video = attrib | ch;
				}
			}
		}
		else				/* display controls C0 */
		{
			if(vgacs[svsp->vga_charset].secondloaded)
			{
				*video = attrib | (ch | CSH);
			}
			else	/* use normal ibm charset for control display*/
			{
				*video = attrib | ch;
			}
		}
	}
}

/*---------------------------------------------------------------------------*
 *	emulator main entry
 *---------------------------------------------------------------------------*/
void
sput (u_char *s, U_char kernel, int len, int page)
{
    register struct video_state *svsp;
    u_short	attrib;
    u_short	ch;

    if(page >= PCVT_NSCREENS)		/* failsafe */
	page = 0;

    svsp = &vs[page];			/* pointer to current screen state */

    if(do_initialization)		/* first time called ? */
	vt_coldinit();			/*   yes, we have to init ourselves */

    if(svsp == vsp)			/* on current displayed page ?	*/
    {
	cursor_pos_valid = 0;			/* do not update cursor */

#if PCVT_SCREENSAVER
	if(scrnsv_active)			/* screen blanked ?	*/
		pcvt_scrnsv_reset();		/* unblank NOW !	*/
	else
		reset_screen_saver = 1;		/* do it asynchronously	*/
#endif /* PCVT_SCREENSAVER */

    }

    attrib = kernel ? kern_attr : svsp->c_attr;

    while (len-- > 0)
    if (ch = *(s++))
    {
	if(svsp->sevenbit)
		ch &= 0x7f;

	if(((ch <= 0x1f) || (ch == 0x7f)) && (svsp->transparent == 0))
	{

	/* always process control-chars in the range 0x00..0x1f, 0x7f !!! */

		if(svsp->dis_fnc)
		{
			if(svsp->lastchar && svsp->m_awm
			   && (svsp->lastrow == svsp->row))
			{
				svsp->cur_offset++;
				svsp->col = 0;
				svsp->lastchar = 0;
				check_scroll(svsp);
			}

			if(svsp->irm)
				bcopy((svsp->Crtat + svsp->cur_offset),
				      (svsp->Crtat + svsp->cur_offset) + 1,
				      (((svsp->maxcol)-1) - svsp->col)*CHR);

			write_char(svsp, attrib, ch);

			vt_selattr(svsp);

			if(svsp->col >= ((svsp->maxcol)-1)
			   && ch != 0x0a && ch != 0x0b && ch != 0x0c)
			{
				svsp->lastchar = 1;
				svsp->lastrow = svsp->row;
			}
			else if(ch == 0x0a || ch == 0x0b || ch == 0x0c)
			{
				svsp->cur_offset -= svsp->col;
				svsp->cur_offset += svsp->maxcol;
				svsp->col = 0;
				svsp->lastchar = 0;
				check_scroll(svsp);	/* check scroll up */
			}
			else
			{
				svsp->cur_offset++;
				svsp->col++;
				svsp->lastchar = 0;
			}
		}
		else
		{
			switch(ch)
			{
				case 0x00:	/* NUL */
				case 0x01:	/* SOH */
				case 0x02:	/* STX */
				case 0x03:	/* ETX */
				case 0x04:	/* EOT */
				case 0x05:	/* ENQ */
				case 0x06:	/* ACK */
					break;

				case 0x07:	/* BEL */
					if(svsp->bell_on)
 					  sysbeep(PCVT_SYSBEEPF/1500, hz/4);
					break;

				case 0x08:	/* BS */
					if(svsp->col > 0)
					{
						svsp->cur_offset--;
						svsp->col--;
					}
					break;

				case 0x09:	/* TAB */
					while(svsp->col < ((svsp->maxcol)-1))
					{
						svsp->cur_offset++;
						if(svsp->
						   tab_stops[++svsp->col])
							break;
					}
					break;

				case 0x0a:	/* LF */
				case 0x0b:	/* VT */
				case 0x0c:	/* FF */
					if(svsp->lnm)
					{
						svsp->cur_offset -= svsp->col;
						svsp->cur_offset +=
							svsp->maxcol;
						svsp->col = 0;
					}
					else
					{
						svsp->cur_offset +=
							svsp->maxcol;
					}
					check_scroll(svsp);
					break;

				case 0x0d:	/* CR */
					svsp->cur_offset -= svsp->col;
					svsp->col = 0;
					break;

				case 0x0e:	/* SO */
					svsp->GL = &svsp->G1;
					break;

				case 0x0f:	/* SI */
					svsp->GL = &svsp->G0;
					break;

				case 0x10:	/* DLE */
				case 0x11:	/* DC1/XON */
				case 0x12:	/* DC2 */
				case 0x13:	/* DC3/XOFF */
				case 0x14:	/* DC4 */
				case 0x15:	/* NAK */
				case 0x16:	/* SYN */
				case 0x17:	/* ETB */
					break;

				case 0x18:	/* CAN */
					svsp->state = STATE_INIT;
					clr_parms(svsp);
					break;

				case 0x19:	/* EM */
					break;

				case 0x1a:	/* SUB */
					svsp->state = STATE_INIT;
					clr_parms(svsp);
					break;

				case 0x1b:	/* ESC */
					svsp->state = STATE_ESC;
					clr_parms(svsp);
					break;

				case 0x1c:	/* FS */
				case 0x1d:	/* GS */
				case 0x1e:	/* RS */
				case 0x1f:	/* US */
				case 0x7f:	/* DEL */
				break;
			}
		}
	}
	else
	{

	/* char range 0x20...0x73, 0x80...0xff processing */
	/* depends on current state */

		switch(svsp->state)
		{
			case STATE_INIT:
				if(svsp->lastchar && svsp->m_awm &&
				   (svsp->lastrow == svsp->row))
				{
					svsp->cur_offset++;
					svsp->col = 0;
					svsp->lastchar = 0;
					check_scroll(svsp);
				}

				if(svsp->irm)
					bcopy  ((svsp->Crtat
						 + svsp->cur_offset),
						(svsp->Crtat
						 + svsp->cur_offset) + 1,
						(((svsp->maxcol)-1)
						 - svsp->col) * CHR);

				write_char(svsp, attrib, ch);

				vt_selattr(svsp);

				if(svsp->col >= ((svsp->maxcol)-1))
				{
					svsp->lastchar = 1;
					svsp->lastrow = svsp->row;
				}
				else
				{
					svsp->lastchar = 0;
					svsp->cur_offset++;
					svsp->col++;
				}
				break;

			case STATE_ESC:
				switch(ch)
				{
					case ' ':	/* ESC sp family */
						svsp->state = STATE_BLANK;
						break;

					case '#':	/* ESC # family */
						svsp->state = STATE_HASH;
						break;

					case '&':	/* ESC & family (HP) */
						if(svsp->vt_pure_mode ==
						   M_HPVT)
						{
							svsp->state =
								STATE_AMPSND;
							svsp->hp_state =
								SHP_INIT;
						}
						else
							svsp->state =
								STATE_INIT;
						break;

					case '(':	/* ESC ( family */
						svsp->state = STATE_BROPN;
						break;

					case ')':	/* ESC ) family */
						svsp->state = STATE_BRCLO;
						break;

					case '*':	/* ESC * family */
						svsp->state = STATE_STAR;
						break;

					case '+':	/* ESC + family */
						svsp->state = STATE_PLUS;
						break;

					case '-':	/* ESC - family */
						svsp->state = STATE_MINUS;
						break;

					case '.':	/* ESC . family */
						svsp->state = STATE_DOT;
						break;

					case '/':	/* ESC / family */
						svsp->state = STATE_SLASH;
						break;

					case '7':	/* SAVE CURSOR */
						vt_sc(svsp);
						svsp->state = STATE_INIT;
						break;

					case '8':	/* RESTORE CURSOR */
						vt_rc(svsp);
						if (!kernel)
							attrib = svsp->c_attr;
						svsp->state = STATE_INIT;
						break;

					case '=': /* keypad application mode */
#if !PCVT_INHIBIT_NUMLOCK
						vt_keyappl(svsp);
#endif
						svsp->state = STATE_INIT;
						break;

					case '>': /* keypad numeric mode */
#if !PCVT_INHIBIT_NUMLOCK
						vt_keynum(svsp);
#endif
						svsp->state = STATE_INIT;
						break;

					case 'D':	/* INDEX */
						vt_ind(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'E':	/* NEXT LINE */
						vt_nel(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'H': /* set TAB at current col */
						svsp->tab_stops[svsp->col] = 1;
						svsp->state = STATE_INIT;
						break;

					case 'M':	/* REVERSE INDEX */
						vt_ri(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'N':	/* SINGLE SHIFT G2 */
						svsp->Gs = &svsp->G2;
						svsp->ss = 1;
						svsp->state = STATE_INIT;
						break;

					case 'O':	/* SINGLE SHIFT G3 */
						svsp->Gs = &svsp->G3;
						svsp->ss = 1;
						svsp->state = STATE_INIT;
						break;

					case 'P':	/* DCS detected */
						svsp->dcs_state = DCS_INIT;
						svsp->state = STATE_DCS;
						break;

					case 'Z': /* What are you = ESC [ c */
						vt_da(svsp);
						svsp->state = STATE_INIT;
						break;

					case '[':	/* CSI detected */
						clr_parms(svsp);
						svsp->state = STATE_CSI;
						break;

					case '\\':	/* String Terminator */
						svsp->state = STATE_INIT;
						break;

					case 'c':	/* hard reset */
						vt_ris(svsp);
						if (!kernel)
							attrib = svsp->c_attr;
						svsp->state = STATE_INIT;
						break;

#if PCVT_SETCOLOR
					case 'd':	/* set color sgr */
						if(color)
						{
							/* set shiftwidth=4 */
							sgr_tab_color
								[svsp->
								 vtsgr] =
								 svsp->c_attr
								 >> 8;
							user_attr =
								sgr_tab_color
								[0] << 8;
						}
						svsp->state = STATE_INIT;
						break;
#endif /* PCVT_SETCOLOR */
					case 'n': /* Lock Shift G2 -> GL */
						svsp->GL = &svsp->G2;
						svsp->state = STATE_INIT;
						break;

					case 'o': /* Lock Shift G3 -> GL */
						svsp->GL = &svsp->G3;
						svsp->state = STATE_INIT;
						break;

					case '}': /* Lock Shift G2 -> GR */
						svsp->GR = &svsp->G2;
						svsp->state = STATE_INIT;
						break;

					case '|': /* Lock Shift G3 -> GR */
						svsp->GR = &svsp->G3;
						svsp->state = STATE_INIT;
						break;

					case '~': /* Lock Shift G1 -> GR */
						svsp->GR = &svsp->G1;
						svsp->state = STATE_INIT;
						break;

					default:
						svsp->state = STATE_INIT;
						break;
				}
				break;

			case STATE_BLANK:        /* ESC space [FG], which are */
                                svsp->state = STATE_INIT; /* currently ignored*/
                        	break;

			case STATE_HASH:
				switch(ch)
				{
					case '3': /* double height top half */
					case '4': /*double height bottom half*/
					case '5': /*single width sngle height*/
					case '6': /*double width sngle height*/
						svsp->state = STATE_INIT;
						break;

					case '8': /* fill sceen with 'E's */
						vt_aln(svsp);
						svsp->state = STATE_INIT;
						break;

					default: /* anything else */
						svsp->state = STATE_INIT;
						break;
				}
				break;

			case STATE_BROPN:	/* designate G0 */
			case STATE_BRCLO:	/* designate G1 */
			case STATE_STAR:	/* designate G2 */
			case STATE_PLUS:	/* designate G3 */
			case STATE_MINUS:	/* designate G1 (96) */
			case STATE_DOT:		/* designate G2 (96) */
			case STATE_SLASH:	/* designate G3 (96) */
				svsp->which[svsp->whichi++] = ch;
				if(ch >= 0x20 && ch <= 0x2f
				   && svsp->whichi <= 2)
					break;
				else if(ch >=0x30 && ch <= 0x7e)
				{
					svsp->which[svsp->whichi] = '\0';
					vt_designate(svsp);
				}
				svsp->whichi = 0;
				svsp->state = STATE_INIT;
				break;

			case STATE_CSIQM:	/* DEC private modes */
				switch(ch)
				{
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':	/* parameters */
						svsp->parms[svsp->parmi] *= 10;
						svsp->parms[svsp->parmi] +=
							(ch -'0');
						break;

					case ';':	/* next parameter */
						svsp->parmi =
						 (svsp->parmi+1 < MAXPARMS) ?
						 svsp->parmi+1 : svsp->parmi;
						break;

					case 'h':	/* set mode */
						vt_set_dec_priv_qm(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'l':	/* reset mode */
						vt_reset_dec_priv_qm(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'n':	/* Reports */
						vt_dsr(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'K': /* selective erase in line */
						vt_sel(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'J':/*selective erase in display*/
						vt_sed(svsp);
						svsp->state = STATE_INIT;
						break;

					default:
						svsp->state = STATE_INIT;
						break;

				}
				break;

			case STATE_CSI:
				switch(ch)
				{
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':	/* parameters */
						svsp->parms[svsp->parmi] *= 10;
						svsp->parms[svsp->parmi] +=
							(ch -'0');
						break;

					case ';':	/* next parameter */
						svsp->parmi =
						 (svsp->parmi+1 < MAXPARMS) ?
						 svsp->parmi+1 : svsp->parmi;
						break;

					case '?':	/* ESC [ ? family */
						svsp->state = STATE_CSIQM;
						break;

					case '@':	/* insert char */
						vt_ic(svsp);
						svsp->state = STATE_INIT;
						break;

					case '"':  /* select char attribute */
						svsp->state = STATE_SCA;
						break;

					case '\'': /* for DECELR/DECSLE */
/* XXX */					/* another state needed -hm */
						break;

					case '!': /* soft terminal reset */
						svsp->state = STATE_STR;
						break;

					case 'A':	/* cursor up */
						vt_cuu(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'B':	/* cursor down */
						vt_cud(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'C':	/* cursor forward */
						vt_cuf(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'D':	/* cursor backward */
						vt_cub(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'H': /* direct cursor addressing*/
						vt_curadr(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'J':	/* erase screen */
						vt_clreos(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'K':	/* erase line */
						vt_clreol(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'L':	/* insert line */
						vt_il(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'M':	/* delete line */
						vt_dl(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'P':	/* delete character */
						vt_dch(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'S':	/* scroll up */
						vt_su(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'T':	/* scroll down */
						vt_sd(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'X':	/* erase character */
						vt_ech(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'c':	/* device attributes */
						vt_da(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'f': /* direct cursor addressing*/
						vt_curadr(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'g':	/* clear tabs */
						vt_clrtab(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'h':	/* set mode(s) */
						vt_set_ansi(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'i':	/* media copy */
						vt_mc(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'l':	/* reset mode(s) */
						vt_reset_ansi(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'm': /* select graphic rendition*/
						vt_sgr(svsp);
						if (!kernel)
							attrib = svsp->c_attr;
						svsp->state = STATE_INIT;
						break;

					case 'n':	/* reports */
						vt_dsr(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'r': /* set scrolling region */
						vt_stbm(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'x': /*request/report parameters*/
						vt_reqtparm(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'y': /* invoke selftest(s) */
						vt_tst(svsp);
						svsp->state = STATE_INIT;
						break;

					case 'z': /* DECELR, ignored */
					case '{': /* DECSLE, ignored */
						svsp->state = STATE_INIT;
						break;

					default:
						svsp->state = STATE_INIT;
						break;
				}
				break;

			case STATE_AMPSND:
				hp_entry(ch,svsp);
				break;

			case STATE_DCS:
				vt_dcsentry(ch,svsp);
				break;

			case STATE_SCA:
				switch(ch)
				{
					case 'q':
						vt_sca(svsp);
						svsp->state = STATE_INIT;
						break;

					default:
						svsp->state = STATE_INIT;
						break;
				}
				break;

			case STATE_STR:
				switch(ch)
				{
					case 'p': /* soft terminal reset */
						vt_str(svsp);
						if (!kernel)
							attrib = svsp->c_attr;
						svsp->state = STATE_INIT;
						break;

					default:
						svsp->state = STATE_INIT;
						break;
				}
				break;

			default:		/* failsafe */
				svsp->state = STATE_INIT;
				break;

		}
	}

	svsp->row = svsp->cur_offset / svsp->maxcol;	/* current row update */

	/* take care of last character on line behaviour */

	if(svsp->lastchar && (svsp->col < ((svsp->maxcol)-1)))
		svsp->lastchar = 0;
    }

    if(svsp == vsp)			/* on current displayed page ?	*/
	cursor_pos_valid = 1;		/* position is valid now */
}

/*---------------------------------------------------------------------------*
 *	this is the absolute cold initialization of the emulator
 *---------------------------------------------------------------------------*/
static void
vt_coldinit(void)
{
	u_short volatile *cp;
	u_short was;
	int nscr, charset;
	int equipment;
	u_short *SaveCrtat;
	struct video_state *svsp;

	Crtat = (u_short *)MONO_BUF;	/* XXX assume static relocation works */
	SaveCrtat = Crtat;
	cp = Crtat + (CGA_BUF-MONO_BUF)/CHR;

	do_initialization = 0;		/* reset init necessary flag */

	/* get the equipment byte from the RTC chip */

	equipment = ((rtcin(RTC_EQUIPMENT)) >> 4) & 0x03;

	switch(equipment)
	{
		case EQ_EGAVGA:

			/* set memory start to CGA == B8000 */

			Crtat = Crtat + (CGA_BUF-MONO_BUF)/CHR;

			/* find out, what monitor is connected */

			was = *cp;
			*cp = (u_short) 0xA55A;
			if (*cp != 0xA55A)
			{
				addr_6845 = MONO_BASE;
				color = 0;
			}
			else
			{
				*cp = was;
				addr_6845 = CGA_BASE;
				color = 1;
			}

			if(vga_test())		/* EGA or VGA ? */
			{
				adaptor_type = VGA_ADAPTOR;
				totalfonts = 8;

				if(color == 0)
				{
					mda2egaorvga();
					Crtat = SaveCrtat; /* mono start */
				}

				/* find out which chipset we are running on */
				vga_type = vga_chipset();
			}
			else
			{
				adaptor_type = EGA_ADAPTOR;
				totalfonts = 4;

				if(color == 0)
				{
					mda2egaorvga();
					Crtat = SaveCrtat; /* mono start */
				}
			}

			/* decouple ega/vga charsets and intensity */
			set_2ndcharset();

			break;

		case EQ_40COLOR:	/* XXX should panic in 40 col mode ! */
		case EQ_80COLOR:
			Crtat = Crtat + (CGA_BUF-MONO_BUF)/CHR;
			addr_6845 = CGA_BASE;
			adaptor_type = CGA_ADAPTOR;
			color = 1;
			totalfonts = 0;
			break;

		case EQ_80MONO:
			addr_6845 = MONO_BASE;
			adaptor_type = MDA_ADAPTOR;
			color = 0;
			totalfonts = 0;
			break;
	}

	/* establish default colors */

	if(color)
	{
		kern_attr = (COLOR_KERNEL_FG | COLOR_KERNEL_BG) << 8;
		user_attr = sgr_tab_color[0] << 8;
	}
	else
	{
		kern_attr = (MONO_KERNEL_FG | MONO_KERNEL_BG) << 8;
		if(adaptor_type == MDA_ADAPTOR)
			user_attr = sgr_tab_imono[0] << 8;
		else
			user_attr = sgr_tab_mono[0] << 8;
	}

	totalscreens = 1;	/* for now until malloced */

	for(nscr = 0, svsp = vs; nscr < PCVT_NSCREENS; nscr++, svsp++)
	{
		svsp->Crtat = Crtat;		/* all same until malloc'ed */
		svsp->Memory = Crtat;		/* until malloc'ed */
		svsp->cur_offset = 0;		/* cursor offset */
		svsp->c_attr = user_attr;	/* non-kernel attributes */
		svsp->bell_on = 1;		/* enable bell */
		svsp->sevenbit = 0;		/* set to 8-bit path */
		svsp->dis_fnc = 0;		/* disable display functions */
		svsp->transparent = 0;		/* disable internal tranparency */
		svsp->lastchar = 0;		/* VTxxx behaviour of last */
						/*            char on line */
		svsp->report_chars = NULL;	/* VTxxx reports init */
		svsp->report_count = 0;		/* VTxxx reports init */
		svsp->state = STATE_INIT;	/* main state machine init */
		svsp->m_awm = 1;		/* enable auto wrap mode */
		svsp->m_om = 0;			/* origin mode = absolute */
		svsp->sc_flag = 0;		/* init saved cursor flag */
		svsp->which_fkl = SYS_FKL;	/* display system fkey-labels */
		svsp->labels_on = 1;		/* if in HP-mode, display */
						/*            fkey-labels */
		svsp->attribute = 0;		/* HP mode init */
		svsp->key = 0;			/* HP mode init */
		svsp->l_len = 0;		/* HP mode init */
		svsp->s_len = 0;		/* HP mode init */
		svsp->m_len = 0;		/* HP mode init */
		svsp->i = 0;			/* HP mode init */
		svsp->vt_pure_mode = M_PUREVT;	/* initial mode: pure VT220*/
		svsp->vga_charset = CH_SET0;	/* use bios default charset */

#if PCVT_24LINESDEF				/* true compatibility */
		svsp->screen_rows = 24;		/* default 24 rows on screen */
#else						/* full screen */
		svsp->screen_rows = 25;		/* default 25 rows on screen */
#endif /* PCVT_24LINESDEF */

		svsp->screen_rowsize = 25;	/* default 25 rows on screen */
		svsp->scrr_beg = 0;		/* scrolling region begin row*/
		svsp->scrr_len = svsp->screen_rows; /* scrolling region length*/
		svsp->scrr_end = svsp->scrr_len - 1;/* scrolling region end */

		if(nscr == 0)
		{
			if(adaptor_type == VGA_ADAPTOR)
			{
				/* only VGA can read cursor shape registers ! */
				/* Preserve initial cursor shape */
				outb(addr_6845,CRTC_CURSTART);
				svsp->cursor_start = inb(addr_6845+1);
				outb(addr_6845,CRTC_CUREND);
				svsp->cursor_end = inb(addr_6845+1);
			}
			else
			{
				/* MDA,HGC,CGA,EGA registers are write-only */
				svsp->cursor_start = 0;
				svsp->cursor_end = 15;
			}
		}
		else
		{
			svsp->cursor_start = vs[0].cursor_start;
			svsp->cursor_end = vs[0].cursor_end;
		}

#ifdef FAT_CURSOR
		svsp->cursor_start = 0;
		svsp->cursor_end = 15;		/* cursor lower scanline */
#endif

		svsp->cursor_on = 1;		/* cursor is on */
		svsp->ckm = 1;			/* normal cursor key mode */
		svsp->irm = 0;			/* replace mode */
		svsp->lnm = 0;			/* CR only */
		svsp->selchar = 0;		/* selective attribute off */
		svsp->G0 = csd_ascii;		/* G0 = ascii	*/
		svsp->G1 = csd_ascii;		/* G1 = ascii	*/
		svsp->G2 = csd_supplemental;	/* G2 = supplemental */
		svsp->G3 = csd_supplemental;	/* G3 = supplemental */
		svsp->GL = &svsp->G0;		/* GL = G0 */
		svsp->GR = &svsp->G2;		/* GR = G2 */
		svsp->whichi = 0;		/* char set designate init */
		svsp->which[0] = '\0';		/* char set designate init */
		svsp->hp_state = SHP_INIT;	/* init HP mode state machine*/
		svsp->dcs_state = DCS_INIT;	/* init DCS mode state machine*/
		svsp->ss  = 0;			/* init single shift 2/3 */
		svsp->Gs  = NULL;		/* Gs single shift 2/3 */
		svsp->maxcol = SCR_COL80;	/* 80 columns now (MUST!!!) */
		svsp->wd132col = 0;		/* help good old WD .. */
		svsp->scroll_lock = 0;		/* scrollock off */

#if PCVT_INHIBIT_NUMLOCK
		svsp->num_lock = 0; 		/* numlock off */
#else
		svsp->num_lock = 1;		/* numlock on */
#endif

		svsp->caps_lock = 0;		/* capslock off */
		svsp->shift_lock = 0;		/* shiftlock off */

#if PCVT_24LINESDEF				/* true compatibility */
		svsp->force24 = 1;		/* force 24 lines */
#else						/* maximum screen size */
		svsp->force24 = 0;		/* no 24 lines force yet */
#endif /* PCVT_24LINESDEF */

		vt_clearudk(svsp);		/* clear vt220 udk's */

		vt_str(svsp);			/* init emulator */

		if(nscr == 0)
		{
			/*
			 * Preserve data on the startup screen that
			 * precedes the cursor position.  Leave the
			 * cursor where it was found.
			 */
			unsigned cursorat;
			int filllen;

			/* CRTC regs 0x0e and 0x0f are r/w everywhere */

			outb(addr_6845, CRTC_CURSORH);
			cursorat = inb(addr_6845+1) << 8;
			outb(addr_6845, CRTC_CURSORL);
			cursorat |= inb(addr_6845+1);

			/*
			 * Reject cursors that are more than one row off a
			 * 25-row screen.  syscons sets the cursor offset
			 * to 0xffff. The scroll up fixup fails for this
			 * because the assignment to svsp->row overflows
			 * and perhaps for other reasons.
			 */
			if (cursorat > 25 * svsp->maxcol)
				cursorat = 25 * svsp->maxcol;

			svsp->cur_offset = cursorat;
			svsp->row = cursorat / svsp->maxcol;
			svsp->col = cursorat % svsp->maxcol;

			if (svsp->row >= svsp->screen_rows)
			{

			/*
			 * Scroll up; this should only happen when
			 * PCVT_24LINESDEF is set
			 */
				int nscroll =
					svsp->row + 1
					- svsp->screen_rows;
				bcopy (svsp->Crtat
				       + nscroll*svsp->maxcol,
				       svsp->Crtat,
				       svsp->screen_rows
				       * svsp->maxcol * CHR);
				svsp->row -= nscroll;
				svsp->cur_offset -=
					nscroll * svsp->maxcol;
			}

			filllen = (svsp->maxcol * svsp->screen_rowsize)
				- svsp->cur_offset;

			if (filllen > 0)
				fillw(user_attr | ' ',
				      svsp->Crtat+svsp->cur_offset,
				      filllen);
		}

#if PCVT_USL_VT_COMPAT
		svsp->smode.mode = VT_AUTO;
		svsp->smode.relsig = svsp->smode.acqsig =
			svsp->smode.frsig = 0;
		svsp->proc = 0;
		svsp->pid = svsp->vt_status = 0;
#endif /* PCVT_USL_VT_COMPAT */

	}

 	for(charset = 0;charset < NVGAFONTS;charset++)
	{
		vgacs[charset].loaded = 0;		/* not populated yet */
		vgacs[charset].secondloaded = 0;	/* not populated yet */

		switch(adaptor_type)
		{
			case VGA_ADAPTOR:

				/*
				 * for a VGA, do not assume any
				 * constant - instead, read the actual
				 * values. This avoid problems with
				 * LCD displays that apparently happen
				 * to use font matrices up to 19
				 * scan lines and 475 scan lines
				 * total in order to make use of the
				 * whole screen area
				 */

				outb(addr_6845, CRTC_VDE);
				vgacs[charset].scr_scanlines =
					inb(addr_6845 + 1);
				outb(addr_6845, CRTC_MAXROW);
				vgacs[charset].char_scanlines =
					inb(addr_6845 + 1);
				break;

			case EGA_ADAPTOR:
				/* 0x5D for 25 lines */
				vgacs[charset].scr_scanlines = 0x5D;
				/* 0x4D for 25 lines */
				vgacs[charset].char_scanlines = 0x4D;
				break;

			case CGA_ADAPTOR:
			case MDA_ADAPTOR:
			default:
				/* These shouldn't be used for CGA/MDA */
				vgacs[charset].scr_scanlines = 0;
				vgacs[charset].char_scanlines = 0;
				break;
		}
		vgacs[charset].screen_size = SIZ_25ROWS; /* set screen size */
 	}

 	vgacs[0].loaded = 1; /* The BIOS loaded this at boot */

	/* set cursor for first screen */

	outb(addr_6845,CRTC_CURSTART);	/* cursor start reg */
	outb(addr_6845+1,vs[0].cursor_start);
	outb(addr_6845,CRTC_CUREND);	/* cursor end reg */
	outb(addr_6845+1,vs[0].cursor_end);

	/* this is to satisfy ddb */

	if(!keyboard_is_initialized)
		kbd_code_init1();
}

/*---------------------------------------------------------------------------*
 *	get kernel memory for virtual screens
 *
 *	CAUTION: depends on "can_do_132col" being set properly, or
 *	depends on vga_type() being run before calling this !!!
 *
 *---------------------------------------------------------------------------*/
void
vt_coldmalloc(void)
{
	int nscr;
	int screen_max_size;

	/* we need to initialize in case we are not the console */

	if(do_initialization)
		vt_coldinit();

	switch(adaptor_type)
	{
		default:
		case MDA_ADAPTOR:
		case CGA_ADAPTOR:
			screen_max_size = MAXROW_MDACGA * MAXCOL_MDACGA * CHR;
			break;

		case EGA_ADAPTOR:
			screen_max_size = MAXROW_EGA * MAXCOL_EGA * CHR;
			break;

		case VGA_ADAPTOR:
			if(can_do_132col)
				screen_max_size =
					MAXROW_VGA * MAXCOL_SVGA * CHR;
			else
				screen_max_size =
					MAXROW_VGA * MAXCOL_VGA * CHR;
	}

	for(nscr = 0; nscr < PCVT_NSCREENS; nscr++)
	{
		if((vs[nscr].Memory =
		    (u_short *)malloc(screen_max_size * 2, M_DEVBUF, M_WAITOK))
		   == NULL)
		{
			printf("pcvt: screen memory malloc failed, "
			       "NSCREEN=%d, nscr=%d\n",
			       PCVT_NSCREENS, nscr);
			break;
		}
		if(nscr != 0)
		{
			vs[nscr].Crtat = vs[nscr].Memory;
			fillw(user_attr | ' ',
				vs[nscr].Crtat,
				vs[nscr].maxcol * vs[nscr].screen_rowsize);
			totalscreens++;
		}
	}
}

/*---------------------------------------------------------------------------*
 *	check if we must scroll up screen
 *---------------------------------------------------------------------------*/
static void
check_scroll(struct video_state *svsp)
{
	if(!svsp->abs_write)
	{
		/* we write within scroll region */

		if(svsp->cur_offset >= ((svsp->scrr_end + 1) * svsp->maxcol))
		{
			/* the following piece of code has to be protected */
			/* from trying to switch to another virtual screen */
			/* while being in there ...                        */

			critical_scroll = 1;		/* flag protect ON */

			roll_up(svsp, 1);		/* rolling up .. */

			svsp->cur_offset -= svsp->maxcol;/* update position */

			if(switch_page != -1)	/* someone wanted to switch ? */
			{
				vgapage(switch_page);	/* yes, then switch ! */
				switch_page = -1;	/* reset switch flag  */
			}

			critical_scroll = 0;		/* flag protect OFF */
	  	}
	}
        else
        {
		/* clip, if outside of screen */

                if (svsp->cur_offset >= svsp->screen_rows * svsp->maxcol)
                        svsp->cur_offset -= svsp->maxcol;
        }
}

/*---------------------------------------------------------------------------*
 *	write to one user function key label
 *---------------------------------------------------------------------------*/
static void
writefkl(int num, u_char *string, struct video_state *svsp)
{
	if((num < 0) || (num > 7))	/* range ok ? */
		return;

	strncpy(svsp->ufkl[num], string, 16); /* save string in static array */

	if(svsp->which_fkl == USR_FKL)
		wrfkl(num,string,svsp);
}

/*---------------------------------------------------------------------------*
 *	write to one system function key label
 *---------------------------------------------------------------------------*/
void
swritefkl(int num, u_char *string, struct video_state *svsp)
{
	if((num < 0) || (num > 7))	/* range ok ? */
		return;

	strncpy(svsp->sfkl[num], string, 16); /* save string in static array */

	if(svsp->which_fkl == SYS_FKL)
		wrfkl(num,string,svsp);
}

/*---------------------------------------------------------------------------*
 *	write function key label onto screen
 *---------------------------------------------------------------------------*/
static void
wrfkl(int num, u_char *string, struct video_state *svsp)
{
	register u_short *p;
	register u_short *p1;
	register int cnt = 0;

	if(!svsp->labels_on || (svsp->vt_pure_mode == M_PUREVT))
		return;

	p = (svsp->Crtat
	     + (svsp->screen_rows * svsp->maxcol)); /* screen_rows+1 line */

	if(svsp->maxcol == SCR_COL80)
	{
		if(num < 4)	/* labels 1 .. 4 */
			p += (num * LABEL_LEN);
		else		/* labels 5 .. 8 */
			p += ((num * LABEL_LEN) + LABEL_MID + 1);
	}
	else
	{
		if(num < 4)	/* labels 1 .. 4 */
			p += (num * (LABEL_LEN + 6));
		else		/* labels 5 .. 8 */
			p += ((num * (LABEL_LEN + 6)) + LABEL_MID + 11);

	}
	p1 = p + svsp->maxcol;	/* second label line */

	while((*string != '\0') && (cnt < 8))
	{
		*p = ((0x70 << 8) + (*string & 0xff));
		p++;
		string++;
		cnt++;
	}
	while(cnt < 8)
	{
		*p = ((0x70 << 8) + ' ');
		p++;
		cnt++;
	}

	while((*string != '\0') && (cnt < 16))
	{
		*p1 = ((0x70 << 8) + (*string & 0xff));
		p1++;
		string++;
		cnt++;
	}
	while(cnt < 16)
	{
		*p1 = ((0x70 << 8) + ' ');
		p1++;
		cnt++;
	}
}

/*---------------------------------------------------------------------------*
 *	remove (=blank) function key labels, row/col and status line
 *---------------------------------------------------------------------------*/
void
fkl_off(struct video_state *svsp)
{
	register u_short *p;
	register int num;
	register int size;

	svsp->labels_on = 0;

	if((vgacs[svsp->vga_charset].screen_size==SIZ_28ROWS) && svsp->force24)
		size = 4;
	else
		size = 3;

	p = (svsp->Crtat + (svsp->screen_rows * svsp->maxcol));

	for(num = 0; num < (size * svsp->maxcol); num++)
		*p++ = ' ';
}

/*---------------------------------------------------------------------------*
 *	(re-) display function key labels, row/col and status line
 *---------------------------------------------------------------------------*/
void
fkl_on(struct video_state *svsp)
{
	svsp->labels_on = 1;

	if(svsp->which_fkl == SYS_FKL)
		sw_sfkl(svsp);
	else if(svsp->which_fkl == USR_FKL)
		sw_ufkl(svsp);
}

/*---------------------------------------------------------------------------*
 *	set emulation mode, switch between pure VTxxx mode and HP/VTxxx mode
 *---------------------------------------------------------------------------*/
void
set_emulation_mode(struct video_state *svsp, int mode)
{
	if(svsp->vt_pure_mode == mode)
		return;

	clr_parms(svsp);		/* escape parameter init */
	svsp->state = STATE_INIT;	/* initial state */
	svsp->scrr_beg = 0;		/* start of scrolling region */
	svsp->sc_flag = 0;		/* invalidate saved cursor position */
	svsp->transparent = 0;		/* disable control code processing */

	if(mode == M_HPVT)		/* vt-pure -> hp/vt-mode */
	{
		svsp->screen_rows = svsp->screen_rowsize - 3;
		if (svsp->force24 && svsp->screen_rows == 25)
			svsp->screen_rows = 24;

		if (svsp->row >= svsp->screen_rows) {
			/* Scroll up */
			int nscroll = svsp->row + 1 - svsp->screen_rows;
			bcopy (svsp->Crtat + nscroll * svsp->maxcol,
			       svsp->Crtat,
			       svsp->screen_rows * svsp->maxcol * CHR);
			svsp->row -= nscroll;
			svsp->cur_offset -= nscroll * svsp->maxcol;
		}

		svsp->vt_pure_mode = M_HPVT;

		if (svsp->vs_tty)
			svsp->vs_tty->t_winsize.ws_row = svsp->screen_rows;

		svsp->scrr_len = svsp->screen_rows;
		svsp->scrr_end = svsp->scrr_len - 1;

		update_hp(svsp);
	}
	else if(mode == M_PUREVT)	/* hp/vt-mode -> vt-pure */
	{
		fillw(user_attr | ' ',
		      svsp->Crtat + svsp->screen_rows * svsp->maxcol,
		      (svsp->screen_rowsize - svsp->screen_rows)
		      * svsp->maxcol);

		svsp->vt_pure_mode = M_PUREVT;

		svsp->screen_rows = svsp->screen_rowsize;
		if (svsp->force24 && svsp->screen_rows == 25)
			svsp->screen_rows = 24;

		if (svsp->vs_tty)
			svsp->vs_tty->t_winsize.ws_row = svsp->screen_rows;

		svsp->scrr_len = svsp->screen_rows;
		svsp->scrr_end = svsp->scrr_len - 1;
	}

#if PCVT_SIGWINCH
	if (svsp->vs_tty && svsp->vs_tty->t_pgrp)
		pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1);
#endif /* PCVT_SIGWINCH */

}

/*---------------------------------------------------------------------------*
 *	initialize user function key labels
 *---------------------------------------------------------------------------*/
void
init_ufkl(struct video_state *svsp)
{
	writefkl(0,(u_char *)"   f1",svsp);	/* init fkey labels */
	writefkl(1,(u_char *)"   f2",svsp);
	writefkl(2,(u_char *)"   f3",svsp);
	writefkl(3,(u_char *)"   f4",svsp);
	writefkl(4,(u_char *)"   f5",svsp);
	writefkl(5,(u_char *)"   f6",svsp);
	writefkl(6,(u_char *)"   f7",svsp);
	writefkl(7,(u_char *)"   f8",svsp);
}

/*---------------------------------------------------------------------------*
 *	initialize system user function key labels
 *---------------------------------------------------------------------------*/
void
init_sfkl(struct video_state *svsp)
{
			    /* 1234567812345678 */
	if(can_do_132col)
				    /* 1234567812345678 */
		swritefkl(0,(u_char *)"132     COLUMNS ",svsp);
	else
		swritefkl(0,(u_char *)" ",svsp);

			    /* 1234567812345678 */
	swritefkl(1,(u_char *)"SOFT-RSTTERMINAL",svsp);

	if(svsp->force24)
		swritefkl(2,(u_char *)"FORCE24 ENABLE *",svsp);
	else
		swritefkl(2,(u_char *)"FORCE24 ENABLE  ",svsp);

#if PCVT_SHOWKEYS	    /* 1234567812345678 */
	if(svsp == &vs[0])
		swritefkl(3,(u_char *)"KEYBSCANDISPLAY ",svsp);
	else
		swritefkl(3,(u_char *)" ",svsp);
#else
	swritefkl(3,(u_char *)" ",svsp);
#endif /* PCVT_SHOWKEYS */

			    /* 1234567812345678 */
	if(svsp->bell_on)
		swritefkl(4,(u_char *)"BELL    ENABLE *",svsp);
	else
		swritefkl(4,(u_char *)"BELL    ENABLE  ",svsp);

	if(svsp->sevenbit)
		swritefkl(5,(u_char *)"8-BIT   ENABLE  ",svsp);
	else
		swritefkl(5,(u_char *)"8-BIT   ENABLE *",svsp);

	swritefkl(6,(u_char *)"DISPLAY FUNCTNS ",svsp);

	swritefkl(7,(u_char *)"AUTOWRAPENABLE *",svsp);
			    /* 1234567812345678 */
}

/*---------------------------------------------------------------------------*
 *	switch display to user function key labels
 *---------------------------------------------------------------------------*/
void
sw_ufkl(struct video_state *svsp)
{
	int i;
	svsp->which_fkl = USR_FKL;
	for(i = 0; i < 8; i++)
		wrfkl(i,svsp->ufkl[i],svsp);
}

/*---------------------------------------------------------------------------*
 *	switch display to system function key labels
 *---------------------------------------------------------------------------*/
void
sw_sfkl(struct video_state *svsp)
{
	int i;
	svsp->which_fkl = SYS_FKL;
	for(i = 0; i < 8; i++)
		wrfkl(i,svsp->sfkl[i],svsp);
}

/*---------------------------------------------------------------------------*
 *	toggle force 24 lines
 *---------------------------------------------------------------------------*/
void
toggl_24l(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->force24)
		{
			svsp->force24 = 0;
			swritefkl(2,(u_char *)"FORCE24 ENABLE  ",svsp);
		}
		else
		{
			svsp->force24 = 1;
			swritefkl(2,(u_char *)"FORCE24 ENABLE *",svsp);
		}
		set_screen_size(svsp, vgacs[(svsp->vga_charset)].screen_size);
	}
}

#if PCVT_SHOWKEYS
/*---------------------------------------------------------------------------*
 *	toggle keyboard scancode display
 *---------------------------------------------------------------------------*/
void
toggl_kbddbg(struct video_state *svsp)
{
	if((svsp->which_fkl == SYS_FKL) && (svsp == &vs[0]))
	{
		if(keyboard_show)
		{
			keyboard_show = 0;
			swritefkl(3,(u_char *)"KEYBSCANDISPLAY ",svsp);
		}
		else
		{
			keyboard_show = 1;
			swritefkl(3,(u_char *)"KEYBSCANDISPLAY*",svsp);
		}
	}
}
#endif /* PCVT_SHOWKEYS */

/*---------------------------------------------------------------------------*
 *	toggle display functions
 *---------------------------------------------------------------------------*/
void
toggl_dspf(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->dis_fnc)
		{
			svsp->dis_fnc = 0;
			swritefkl(6,(u_char *)"DISPLAY FUNCTNS ",svsp);
		}
		else
		{
			svsp->dis_fnc = 1;
			swritefkl(6,(u_char *)"DISPLAY FUNCTNS*",svsp);
		}
	}
}

/*---------------------------------------------------------------------------*
 *	auto wrap on/off
 *---------------------------------------------------------------------------*/
void
toggl_awm(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->m_awm)
		{
			svsp->m_awm = 0;
			swritefkl(7,(u_char *)"AUTOWRAPENABLE  ",svsp);
		}
		else
		{
			svsp->m_awm = 1;
			swritefkl(7,(u_char *)"AUTOWRAPENABLE *",svsp);
		}
	}
}

/*---------------------------------------------------------------------------*
 *	bell on/off
 *---------------------------------------------------------------------------*/
void
toggl_bell(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->bell_on)
		{
			svsp->bell_on = 0;
			swritefkl(4,(u_char *)"BELL    ENABLE  ",svsp);
		}
		else
		{
			svsp->bell_on = 1;
			swritefkl(4,(u_char *)"BELL    ENABLE *",svsp);
		}
	}
}

/*---------------------------------------------------------------------------*
 *	7/8 bit usage
 *---------------------------------------------------------------------------*/
void
toggl_sevenbit(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->sevenbit)
		{
			svsp->sevenbit = 0;
			swritefkl(5,(u_char *)"8-BIT   ENABLE *",svsp);
		}
		else
		{
			svsp->sevenbit = 1;
			swritefkl(5,(u_char *)"8-BIT   ENABLE  ",svsp);
		}
	}
}

/*---------------------------------------------------------------------------*
 *	80 / 132 columns
 *---------------------------------------------------------------------------*/
void
toggl_columns(struct video_state *svsp)
{
	if(svsp->which_fkl == SYS_FKL)
	{
		if(svsp->maxcol == SCR_COL132)
		{
			if(vt_col(svsp, SCR_COL80))
				svsp->maxcol = 80;
		}
		else
		{
			if(vt_col(svsp, SCR_COL132))
				svsp->maxcol = 132;
		}
	}
}

/*---------------------------------------------------------------------------*
 *	toggle vga 80/132 column operation
 *---------------------------------------------------------------------------*/
int
vt_col(struct video_state *svsp, int cols)
{
	if(vga_col(svsp, cols) == 0)
		return(0);

	if(cols == SCR_COL80)
		swritefkl(0,(u_char *)"132     COLUMNS ",svsp);
	else
		swritefkl(0,(u_char *)"132     COLUMNS*",svsp);

	fillw(user_attr | ' ',
		svsp->Crtat,
		svsp->maxcol * svsp->screen_rowsize);

	clr_parms(svsp);		/* escape parameter init */
	svsp->state = STATE_INIT;	/* initial state */
	svsp->col = 0;			/* init row */
	svsp->row = 0;			/* init col */
	svsp->cur_offset = 0;		/* cursor offset init */
	svsp->sc_flag = 0;		/* invalidate saved cursor position */
	svsp->scrr_beg = 0;		/* reset scrolling region */
	svsp->scrr_len = svsp->screen_rows; /*reset scrolling region legnth */
	svsp->scrr_end = svsp->scrr_len - 1;
	svsp->transparent = 0;		/* disable control code processing */
	svsp->selchar = 0;		/* selective attr off */
	vt_initsel(svsp);		/* re-init sel attr */

	update_hp(svsp);		/* update labels, row/col, page ind */

	/* Update winsize struct to reflect screen size */

	if(svsp->vs_tty)
	{
		svsp->vs_tty->t_winsize.ws_row = svsp->screen_rows;
		svsp->vs_tty->t_winsize.ws_col = svsp->maxcol;

		svsp->vs_tty->t_winsize.ws_xpixel =
			(cols == SCR_COL80)? 720: 1056;
		svsp->vs_tty->t_winsize.ws_ypixel = 400;

#if PCVT_SIGWINCH
		if(svsp->vs_tty->t_pgrp)
			pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1);
#endif /* PCVT_SIGWINCH */
	}

	return(1);
}

/*---------------------------------------------------------------------------*
 *	update HP stuff on screen
 *---------------------------------------------------------------------------*/
void
update_hp(struct video_state *svsp)
{
	if(svsp->vt_pure_mode != M_HPVT)
		return;

	fillw (user_attr | ' ',
	       svsp->Crtat + svsp->screen_rows * svsp->maxcol,
	       (svsp->screen_rowsize - svsp->screen_rows) * svsp->maxcol);

	if (!svsp->labels_on)
		return;

	/* update fkey labels */

	fkl_off(svsp);
	fkl_on(svsp);

	if(vsp == svsp)
	{
		/* update current displayed screen indicator */

		*((svsp->Crtat + ((svsp->screen_rows + 2) * svsp->maxcol))
		  + svsp->maxcol - 3) = user_attr | '[';
		*((svsp->Crtat + ((svsp->screen_rows + 2) * svsp->maxcol))
		  + svsp->maxcol - 2) = user_attr | current_video_screen + '0';
		*((svsp->Crtat + ((svsp->screen_rows + 2) * svsp->maxcol))
		  + svsp->maxcol - 1) = user_attr | ']';
	}
}

/*---------------------------------------------------------------------------*
 *	initialize ANSI escape sequence parameter buffers
 *---------------------------------------------------------------------------*/
void
clr_parms(struct video_state *svsp)
{
	register int i;
	for(i=0; i < MAXPARMS; i++)
		svsp->parms[i] = 0;
	svsp->parmi = 0;
}


/*---------------------------------------------------------------------------*
 *
 *	partial HP 2392 ANSI mode Emulator
 *	==================================
 *
 *	this part takes over the emulation of some escape sequences
 *	needed to handle the function key labels
 *
 *	They are modeled after the corresponding escape sequences
 *	introduced with the HP2392 terminals from Hewlett-Packard.
 *
 *	see:
 *	"HP2392A, Display Terminal Reference Manual",
 *	HP Manual Part Number 02390-90001
 *	and:
 *	Reference Manual Supplement
 *	"2392A Display Terminal Option 049, ANSI Operation"
 *	HP Manual Part Number 02390-90023EN
 *
 *---------------------------------------------------------------------------*/

static void
hp_entry(U_char ch, struct video_state *svsp)
{
	switch(svsp->hp_state)
	{
		case SHP_INIT:
			switch(ch)
			{
				case 'f':
					svsp->hp_state = SHP_AND_F;
					svsp->attribute = 0;
					svsp->key = 0;
					svsp->l_len = 0;
					svsp->s_len = 0;
					svsp->i = 0;
					break;

				case 'j':
					svsp->m_len = 0;
					svsp->hp_state = SHP_AND_J;
					break;

				case 's':
					svsp->hp_state = SHP_AND_ETE;
					break;

				default:
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					break;
			}
			break;

		case SHP_AND_F:
			if((ch >= '0') && (ch <= '8'))
			{
				svsp->attribute = ch;
				svsp->hp_state = SHP_AND_Fa;
			}
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_Fa:
			if(ch == 'a')
				svsp->hp_state = SHP_AND_Fak;
			else if(ch == 'k')
			{
				svsp->key = svsp->attribute;
				svsp->hp_state = SHP_AND_Fakd;
			}
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_Fak:
			if((ch >= '1') && (ch <= '8'))
			{
				svsp->key = ch;
				svsp->hp_state = SHP_AND_Fak1;
			}
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_Fak1:
			if(ch == 'k')
				svsp->hp_state = SHP_AND_Fakd;
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_Fakd:
			if(svsp->l_len > 16)
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			else if(ch >= '0' && ch <= '9')
			{
				svsp->l_len *= 10;
				svsp->l_len += (ch -'0');
			}
			else if(ch == 'd')
				svsp->hp_state = SHP_AND_FakdL;
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_FakdL:
			if(svsp->s_len > 80)
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			else if(ch >= '0' && ch <= '9')
			{
				svsp->s_len *= 10;
				svsp->s_len += (ch -'0');
			}
			else if(ch == 'L')
			{
				svsp->hp_state = SHP_AND_FakdLl;
				svsp->transparent = 1;
			}
			else
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
			}
			break;

		case SHP_AND_FakdLl:
			svsp->l_buf[svsp->i] = ch;
			if(svsp->i >= svsp->l_len-1)
			{
				svsp->hp_state = SHP_AND_FakdLls;
				svsp->i = 0;
				if(svsp->s_len == 0)
				{
					svsp->state = STATE_INIT;
					svsp->hp_state = SHP_INIT;
					svsp->transparent = 0;
					svsp->i = 0;
					svsp->l_buf[svsp->l_len] = '\0';
					svsp->s_buf[svsp->s_len] = '\0';
					writefkl((svsp->key - '0' -1),
						 svsp->l_buf, svsp);
				}
			}
			else
				svsp->i++;
			break;

		case SHP_AND_FakdLls:
			svsp->s_buf[svsp->i] = ch;
			if(svsp->i >= svsp->s_len-1)
			{
				svsp->state = STATE_INIT;
				svsp->hp_state = SHP_INIT;
				svsp->transparent = 0;
				svsp->i = 0;
				svsp->l_buf[svsp->l_len] = '\0';
				svsp->s_buf[svsp->s_len] = '\0';
				writefkl((svsp->key - '0' -1), svsp->l_buf,
					 svsp);
			}
			else
				svsp->i++;
			break;

		case SHP_AND_J:
			switch(ch)
			{
				case '@':	/* enable user keys, remove */
						/* all labels & status from */
						/* screen 		    */
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					fkl_off(svsp);
					break;

				case 'A':	/* enable & display "modes" */
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					fkl_on(svsp);
					sw_sfkl(svsp);
					break;

				case 'B':	/* enable & display "user"  */
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					fkl_on(svsp);
					sw_ufkl(svsp);
					break;

				case 'C':	/* remove (clear) status line*/
						/* and restore current labels*/
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					fkl_on(svsp);
					break;

				case 'R':	/* enable usr/menu keys */
						/* and fkey label modes */
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					break;

				case 'S':	/* disable usr/menu keys */
						/* and fkey label modes */
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					break;

				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9': /* parameters for esc & j xx L mm */
					svsp->m_len *= 10;
					svsp->m_len += (ch -'0');
					break;

				case 'L':
					svsp->hp_state = SHP_AND_JL;
					svsp->i = 0;
					svsp->transparent = 1;
					break;

				default:
					svsp->hp_state = SHP_INIT;
					svsp->state = STATE_INIT;
					break;

			}
			break;


		case SHP_AND_JL:
			svsp->m_buf[svsp->i] = ch;
			if(svsp->i >= svsp->m_len-1)
			{
				svsp->state = STATE_INIT;
				svsp->hp_state = SHP_INIT;
				svsp->transparent = 0;
				svsp->i = 0;
				svsp->m_buf[svsp->m_len] = '\0';
				/* display status line */
				/* needs to be implemented */
				/* see 2392 man, 3-14 */

			}
			else
				svsp->i++;
			break;

		case SHP_AND_ETE:	/* eat chars until uppercase */
			if(ch >= '@' && ch <= 'Z')
			{
				svsp->hp_state = SHP_INIT;
				svsp->state = STATE_INIT;
				svsp->transparent = 0;
			}
			break;

		default:
			svsp->hp_state = SHP_INIT;
			svsp->state = STATE_INIT;
			svsp->transparent = 0;
			break;
	}
}

#endif	/* NVT > 0 */

/* ------------------------- E O F ------------------------------------------*/

