Coherent4.2.10/conf/vtkb/src/vtkb.c

Compare this file to the similar file:
Show the results in this format:

/* $Header: /ker/io.386/RCS/vtkb.c,v 1.3 93/08/19 10:39:40 nigel Exp Locker: nigel $ */
/*
 * virtual console, nonloadable keyboard driver
 *
 * $Log:	vtkb.c,v $
 * Revision 1.3  93/08/19  10:39:40  nigel
 * r83 ioctl (), corefile, new headers
 * 
 * Revision 1.2  93/08/19  04:03:29  nigel
 * Nigel's R83
 */

#include <common/_tricks.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <signal.h>
#include <stddef.h>

#include <kernel/trace.h>
#include <sys/coherent.h>
#include <sys/uproc.h>
#include <sys/con.h>
#include <sys/devices.h>
#include <sys/tty.h>
#include <sys/sched.h>
#include <sys/silo.h>
#include <sys/kb.h>
#include <sys/vt.h>
#include <sys/vtkd.h>

/************************* Hardware Defines *****************************/

#define	SPC	0xF4			/* Special encoding */
#define XXX	0xF5			/* Non-character */
#define	KBDATA	0x60			/* Keyboard data */
#define	KBCTRL	0x61			/* Keyboard control */
#define	KBFLAG	0x80			/* Keyboard reset flag */
#define	LEDCMD	0xED			/* status indicator command */
#define	KBACK	0xFA			/* status indicator acknowledge */
#define	EXTENDED0 0xE0			/* extended key seq initiator */
#define	EXTENDED1 0xE1			/* extended key seq initiator */

#define	KEYUP	0x80			/* Key up change */
#define	KEYSC	0x7F			/* Key scan code mask */
#define	LSHIFT	(0x2A - 1)		/* Left shift key */
#define LSHIFTA (0x2B - 1)		/* Alternate left-shift key */
#define	RSHIFT	(0x36 - 1)		/* Right shift key */
#define	CTRLkb	(0x1D - 1)		/* Control key */
/*-- #define	CAPLOCK	(0x1D - 1)--*/		/* Control key */
#define	ALTkb	(0x38 - 1)		/* Alt key or ALT GR */
#define	CAPLOCK	(0x3A - 1)		/* Caps lock key */
/*-- #define	CTRL	(0x3A - 1)--*/		/* Caps lock key */
#define	NUMLOCK	(0x45 - 1)		/* Numeric lock key */
#define	DELETE	(0x53 - 1)		/* Del, as in CTRL-ALT-DEL */
#define BACKSP	(0x0E - 1)		/* Back space */
#define SCRLOCK	(0x46 - 1)		/* Scroll lock */

/* Shift flags */
#define	SRS	0x01			/* Right shift key on */
#define	SLS	0x02			/* Left shift key on */
#define CTS	0x04			/* Ctrl key on */
#define ALS	0x08			/* Alt key on */
#define CPLS	0x10			/* Caps lock on */
#define NMLS	0x20			/* Num lock on */
#define AKPS	0x40			/* Alternate keypad shift */
#define SHFT	0x80			/* Shift key flag */
#define	AGS	0x100			/* Alt Graphics on */

/* Function key information */
#define	NFKEY	50			/* Number of settable functions */
#define	NFCHAR	150			/* Number of characters settable */
#define	NFBUF	(NFKEY * 2 + NFCHAR + 1)	/* Size of buffer */


/************************* Data Defines ******************************/


#define	ESCAPE_CHAR	'\x1B'
#define	ESCAPE_STRING	"\x1B"
#define	HEXFF_STRING	"\xFF"
#define	DELETE_STRING	"\x7F"

#define SS0	0			/* No shift */
#define SS1	(SLS | SRS | CTS)		/* Shift, Ctrl */
#define SES	(SLS | SRS)		/* Shift */
#define LET	(SLS | SRS | CPLS | CTS)	/* Shift, Caps, Ctrl */
#define KEY	(SLS | SRS | NMLS | AKPS)	/* Shift, Num, Alt keypad */


/**************************** X Stuff ************************************/


#define TIMER_CTL    0x43                     /* Timer control */
#define TIMER_CNT    0x42                     /* Timer counter */
#define SPEAKER_CTL  0x61                     /* Speaker control */



/************************** Tables ************************************/

/*
 * Default function key strings (terminated by -1)
 */

static char * deffuncs [] = {

	ESCAPE_STRING "[M" HEXFF_STRING,	/* F1 */
	ESCAPE_STRING "[N" HEXFF_STRING,	/* F2 */
	ESCAPE_STRING "[O" HEXFF_STRING,	/* F3 */
	ESCAPE_STRING "[P" HEXFF_STRING, 	/* F4 */
	ESCAPE_STRING "[Q" HEXFF_STRING,	/* F5 */
	ESCAPE_STRING "[R" HEXFF_STRING,	/* F6 */
	ESCAPE_STRING "[S" HEXFF_STRING,	/* F7 */
	ESCAPE_STRING "[T" HEXFF_STRING,	/* F8 */
	ESCAPE_STRING "[U" HEXFF_STRING,	/* F9 */
	ESCAPE_STRING "[V" HEXFF_STRING,	/* F10 - historical value */
	/* No F11 or F12 on these keyboards */

	/* Shifted function keys */
	ESCAPE_STRING "[Y" HEXFF_STRING,	/* sF1 */
	ESCAPE_STRING "[Z" HEXFF_STRING,	/* sF2 */
	ESCAPE_STRING "[a" HEXFF_STRING,	/* sF3 */
	ESCAPE_STRING "[b" HEXFF_STRING, 	/* sF4 */
	ESCAPE_STRING "[c" HEXFF_STRING,	/* sF5 */
	ESCAPE_STRING "[d" HEXFF_STRING,	/* sF6 */
	ESCAPE_STRING "[e" HEXFF_STRING,	/* sF7 */
	ESCAPE_STRING "[f" HEXFF_STRING,	/* sF8 */
	ESCAPE_STRING "[g" HEXFF_STRING,	/* sF9 */
	ESCAPE_STRING "[h" HEXFF_STRING,	/* sF10 */

	/* Ctrl-ed function keys */
	ESCAPE_STRING "[k" HEXFF_STRING,	/* cF1 */
	ESCAPE_STRING "[l" HEXFF_STRING,	/* cF2 */
	ESCAPE_STRING "[m" HEXFF_STRING,	/* cF3 */
	ESCAPE_STRING "[n" HEXFF_STRING,	/* cF4 */
	ESCAPE_STRING "[o" HEXFF_STRING,	/* cF5 */
	ESCAPE_STRING "[p" HEXFF_STRING,	/* cF6 */
	ESCAPE_STRING "[q" HEXFF_STRING,	/* cF7 */
	ESCAPE_STRING "[r" HEXFF_STRING,	/* cF8 */
	ESCAPE_STRING "[s" HEXFF_STRING,	/* cF9 */
	ESCAPE_STRING "[t" HEXFF_STRING,	/* cF10 */

	/* Ctrl-shifted function keys */
	ESCAPE_STRING "[w" HEXFF_STRING,	/* csF1 */
	ESCAPE_STRING "[x" HEXFF_STRING,	/* csF2 */
	ESCAPE_STRING "[y" HEXFF_STRING,	/* csF3 */
	ESCAPE_STRING "[z" HEXFF_STRING,	/* csF4 */
	ESCAPE_STRING "[@" HEXFF_STRING,	/* csF5 */
	ESCAPE_STRING "[[" HEXFF_STRING,	/* csF6 */
	ESCAPE_STRING "[\\" HEXFF_STRING,	/* csF7 */
	ESCAPE_STRING "[]" HEXFF_STRING,	/* csF8 */
	ESCAPE_STRING "[^" HEXFF_STRING,	/* csF9 */
	ESCAPE_STRING "[_" HEXFF_STRING,	/* csF10 */

	/* Alt keys -- use original 83-key setting since these are
	 * not defined for virtual terms; actually, many will never
	 * be used since intercepted by virtual term code, but 
	 * should be there in case someone defines like 1 virtual term
	 * so the keys should return something useful.
	 */
	ESCAPE_STRING "[1y" HEXFF_STRING,	/* aF1 */
	ESCAPE_STRING "[2y" HEXFF_STRING,	/* aF2 */
	ESCAPE_STRING "[3y" HEXFF_STRING,	/* aF3 */
	ESCAPE_STRING "[4y" HEXFF_STRING,	/* aF4 */
	ESCAPE_STRING "[5y" HEXFF_STRING,	/* aF5 */
	ESCAPE_STRING "[6y" HEXFF_STRING,	/* aF6 */
	ESCAPE_STRING "[7y" HEXFF_STRING,	/* aF7 */
	ESCAPE_STRING "[8y" HEXFF_STRING,	/* aF8 */
	ESCAPE_STRING "[9y" HEXFF_STRING,	/* aF9 */
	ESCAPE_STRING "[0y" HEXFF_STRING	/* aF10 */
};

/* The keypad is translated by the following table,
 * the first entry is the normal sequence, the second the shifted,
 * and the third the alternate keypad sequence.
 */

static char * keypad [][3] = {
	{ ESCAPE_STRING "[H",  "7", ESCAPE_STRING "?w" },	/* 71 */
	{ ESCAPE_STRING "[A",  "8", ESCAPE_STRING "?x" },	/* 72 */
	{ ESCAPE_STRING "[I",  "9", ESCAPE_STRING "?y" },	/* 73 */
	{ ESCAPE_STRING "[D",  "4", ESCAPE_STRING "?t" },	/* 75 */
	{ ESCAPE_STRING "7",   "5", ESCAPE_STRING "?u" },	/* 76 */
	{ ESCAPE_STRING "[C",  "6", ESCAPE_STRING "?v" },	/* 77 */
	{ ESCAPE_STRING "[F",  "1", ESCAPE_STRING "?q" },	/* 79 */
	{ ESCAPE_STRING "[B",  "2", ESCAPE_STRING "?r" },	/* 80 */
	{ ESCAPE_STRING "[G",  "3", ESCAPE_STRING "?s" },	/* 81 */
	{ ESCAPE_STRING "[L",  "0", ESCAPE_STRING "?p" },	/* 82 */
	{ DELETE_STRING ,      ".", ESCAPE_STRING "?n" }	/* 83 */
};


/*
 * French Tables for converting key code to ASCII.
 * lmaptab specifies unshifted conversion,
 * umaptab specifies shifted conversion,
 * smaptab specifies the shift states which are active.
 * An entry of XXX says the key is dead.
 * An entry of SPC requires further processing.
 *
 * Key codes:
 *	ESC .. <- == 1 .. 14
 *	-> .. \n == 15 .. 28
 *	CTRL .. ` == 29 .. 41
 *	^ Shift .. PrtSc == 42 .. 55
 * 	ALT .. CapsLock == 56 .. 58
 *	F1 .. F10 == 59 .. 68
 *	NumLock .. Del == 69 .. 83
 *	ISO, F11, F12 == 86 .. 88
 */

static unsigned char fr_agmaptab [] ={					/* Alt Gr */
	       XXX,  XXX,  '~',  '#',  '{',  '[',  '|',		/* 1 - 7 */
	 '`', '\\',  '^',  '@',  ']',  '}',  XXX,  XXX,		/* 8 - 15 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 16 - 23 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 24 - 31 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 32 - 39 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 40 - 47 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 48 - 55 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 56 - 63 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 64 - 71 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 72 - 79 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};

static unsigned char fr_lmaptab [] ={
       ESCAPE_CHAR,  '&','\202', '"', '\'',  '(',  '-',		/* 1 - 7 */
	'\212','_','\207','\205',')',  '=', '\b', '\t',		/* 8 - 15 */
	 'a',  'z',  'e',  'r',  't',  'y',  'u',  'i',		/* 16 - 23 */
	 'o',  'p','\260', '$', '\r',  XXX,  'q',  's',		/* 24 - 31 */
	 'd',  'f',  'g',  'h',  'j',  'k',  'l',  'm',		/* 32 - 39 */
	 '\227','\375', XXX,'*',  'w',  'x',  'c',  'v',		/* 40 - 47 */
	 'b',  'n',  ',',  ';',  ':',  SPC,  XXX,  SPC,		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC,  XXX,  XXX,  '<',  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};

static unsigned char fr_umaptab [] ={
       ESCAPE_CHAR,  '1',  '2',  '3',  '4',  '5',  '6',		/* 1 - 7 */
	 '7',  '8',  '9',  '0','\370', '+', '\b',  SPC,		/* 8 - 15 */
	 'A',  'Z',  'E',  'R',  'T',  'Y',  'U',  'I',		/* 16 - 23 */
	 'O',  'P','\261','\234','\r', XXX,  'Q',  'S',		/* 24 - 31 */
	 'D',  'F',  'G',  'H',  'J',  'K',  'L',  'M',		/* 32 - 39 */
	 '%','\300', XXX,'\346',  'W',  'X',  'C',  'V',		/* 40 - 47 */
	 'B',  'N',  '?',  '.',  '/',  SPC,  XXX,  SPC,		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC,  XXX,  XXX,  '>',  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};

static unsigned char fr_de_smaptab [] ={
	       SS0,  SES,  SS1,  SES,  SES,  SES,  SS1,		/* 1 - 7 */
	 SES,  SES,  SES,  SES,  SS1,  SES,  CTS,  SES,		/* 8 - 15 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  LET,		/* 16 - 23 */
	 LET,  LET,  SS1,  SS1,  CTS, SHFT,  LET,  LET,		/* 24 - 31 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  SES,		/* 32 - 39 */
	 SES,  SS1, SHFT,  SS1,  LET,  LET,  LET,  LET,		/* 40 - 47 */
	 LET,  LET,  LET,  SES,  SES,  SES, SHFT,  SES,		/* 48 - 55 */
	SHFT,  SS1, SHFT,  SS1,  SS1,  SS1,  SS1,  SS1,		/* 56 - 63 */
	 SS1,  SS1,  SS1,  SS1,  SS1, SHFT,  KEY,  KEY,		/* 64 - 71 */
	 KEY,  KEY,  SS0,  KEY,  KEY,  KEY,  SS0,  KEY,		/* 72 - 79 */
	 KEY,  KEY,  KEY,  KEY,  SS0,  SS0,  SES,  SS0,		/* 80 - 87 */
	 SS0
};

/*
 * U.S. Tables for converting key code to ASCII.
 * lmaptab specifies unshifted conversion,
 * umaptab specifies shifted conversion,
 * smaptab specifies the shift states which are active.
 * An entry of XXX says the key is dead.
 * An entry of SPC requires further processing.
 *
 * Key codes:
 *	ESC .. <- == 1 .. 14
 *	-> .. \n == 15 .. 28
 *	CTRL .. ` == 29 .. 41
 *	^ Shift .. PrtSc == 42 .. 55
 * 	ALT .. CapsLock == 56 .. 58
 *	F1 .. F10 == 59 .. 68
 *	NumLock .. Del == 69 .. 83
 */

static unsigned char us_lmaptab [] ={
       ESCAPE_CHAR,  '1',  '2',  '3',  '4',  '5',  '6',		/* 1 - 7 */
	 '7',  '8',  '9',  '0',  '-',  '=', '\b', '\t',		/* 8 - 15 */
	 'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',		/* 16 - 23 */
	 'o',  'p',  '[',  ']', '\r',  XXX,  'a',  's',		/* 24 - 31 */
	 'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',		/* 32 - 39 */
	 '\'', '`',  XXX,  '\\', 'z',  'x',  'c',  'v',		/* 40 - 47 */
	 'b',  'n',  'm',  ',',  '.',  '/',  XXX,  '*',		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC					/* 80 - 83 */
};

static unsigned char us_umaptab [] ={
       ESCAPE_CHAR,  '!',  '@',  '#',  '$',  '%',  '^',		/* 1 - 7 */
	 '&',  '*',  '(',  ')',  '_',  '+', '\b',  SPC,		/* 8 - 15 */
	 'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',		/* 16 - 23 */
	 'O',  'P',  '{',  '}', '\r',  XXX,  'A',  'S',		/* 24 - 31 */
	 'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',		/* 32 - 39 */
	 '"',  '~',  XXX,  '|',  'Z',  'X',  'C',  'V',		/* 40 - 47 */
	 'B',  'N',  'M',  '<',  '>',  '?',  XXX,  '*',		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC					/* 80 - 83 */
};

static unsigned char us_smaptab [] ={
	       SS0,  SES,  SS1,  SES,  SES,  SES,  SS1,		/* 1 - 7 */
	 SES,  SES,  SES,  SES,  SS1,  SES,  CTS,  SES,		/* 8 - 15 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  LET,		/* 16 - 23 */
	 LET,  LET,  SS1,  SS1,  CTS, SHFT,  LET,  LET,		/* 24 - 31 */
	 LET,  LET,  LET,  LET,  LET,  LET,  LET,  SES,		/* 32 - 39 */
	 SES,  SS1, SHFT,  SS1,  LET,  LET,  LET,  LET,		/* 40 - 47 */
	 LET,  LET,  LET,  SES,  SES,  SES, SHFT,  SES,		/* 48 - 55 */
	SHFT,  SS1, SHFT,  SS1,  SS1,  SS1,  SS1,  SS1,		/* 56 - 63 */
	 SS1,  SS1,  SS1,  SS1,  SS1, SHFT,  KEY,  KEY,		/* 64 - 71 */
	 KEY,  KEY,  SS0,  KEY,  KEY,  KEY,  SS0,  KEY,		/* 72 - 79 */
	 KEY,  KEY,  KEY,  KEY					/* 80 - 83 */
};

/*
 * German Tables for converting key code to ASCII.
 * lmaptab specifies unshifted conversion,
 * umaptab specifies shifted conversion,
 * smaptab specifies the shift states which are active.
 * An entry of XXX says the key is dead.
 * An entry of SPC requires further processing.
 *
 * Key codes:
 *	ESC .. <- == 1 .. 14
 *	-> .. \n == 15 .. 28
 *	CTRL .. ` == 29 .. 41
 *	^ Shift .. PrtSc == 42 .. 55
 * 	ALT .. CapsLock == 56 .. 58
 *	F1 .. F10 == 59 .. 68
 *	NumLock .. Del == 69 .. 83
 *	ISO, F11, F12 == 86 .. 88
 */

unsigned char de_agmaptab [] ={					/* Alt Gr */
	       XXX,  XXX,'\375','\374', XXX,  XXX,  XXX,		/* 1 - 7 */
	 '{',  '[',  ']',  '}', '\\',  XXX,  XXX,  XXX,		/* 8 - 15 */
	 '@',  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 16 - 23 */
	 XXX,  XXX,  XXX,  '~',  XXX,  XXX,  XXX,  XXX,		/* 24 - 31 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 32 - 39 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 40 - 47 */
	 XXX,  XXX,'\346', XXX,  XXX,  XXX,  XXX,  XXX,		/* 48 - 55 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 56 - 63 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 64 - 71 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  XXX,		/* 72 - 79 */
	 XXX,  XXX,  XXX,  XXX,  XXX,  XXX,  '|',  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};

static unsigned char de_lmaptab [] ={
       ESCAPE_CHAR,  '1',  '2',  '3',  '4',  '5',  '6',		/* 1 - 7 */
	 '7',  '8',  '9',  '0','\341','\'', '\b', '\t',		/* 8 - 15 */
	 'q',  'w',  'e',  'r',  't',  'z',  'u',  'i',		/* 16 - 23 */
	 'o',  'p','\201', '+', '\r',  XXX,  'a',  's',		/* 24 - 31 */
	 'd',  'f',  'g',  'h',  'j',  'k',  'l','\224',	/* 32 - 39 */
	'\204','^',  XXX,  '#',  'y', 'x',  'c',  'v',		/* 40 - 47 */
	 'b',  'n',  'm',  ',',  '.',  SPC,  XXX,  SPC,		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC,  XXX,  XXX,  '<',  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};

static unsigned char de_umaptab [] ={
       ESCAPE_CHAR,  '!',  '"','\025', '$',  '%',  '&',		/* 1 - 7 */
	 '/',  '(',  ')',  '=',  '?',  '`', '\b',  SPC,		/* 8 - 15 */
	 'Q',  'W',  'E',  'R',  'T',  'Z',  'U',  'I',		/* 16 - 23 */
	 'O',  'P','\232',  '*', '\r',  XXX,  'A',  'S',	/* 24 - 31 */
	 'D',  'F',  'G',  'H',  'J',  'K',  'L','\231',	/* 32 - 39 */
	'\216','\370', XXX,'\'',  'Y',  'X',  'C',  'V',		/* 40 - 47 */
	 'B',  'N',  'M',  ';',  ':',  SPC,  XXX,  SPC,		/* 48 - 55 */
	 XXX,  ' ',  XXX,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 56 - 63 */
	 SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,  SPC,		/* 64 - 71 */
	 SPC,  SPC,  '-',  SPC,  SPC,  SPC,  '+',  SPC,		/* 72 - 79 */
	 SPC,  SPC,  SPC,  SPC,  XXX,  XXX,  '>',  XXX,		/* 80 - 87 */
	 XXX							/* 88 */
};




/************************** Functions. ****************************/

int	vtmmstart ();
int	vtmmwrite ();
void	vtmmwatch ();


/************************** Virtual Term Stuff ********************/

/* constants for vtdata [] */
#define VT_VGAPORT	0x3D4
#define VT_MONOPORT	0x3B4

#define VT_MONOBASE	(SEL_VIDEOa)
#define VT_VGABASE	(SEL_VIDEOb)

/*
	Patchable table entries.
	Indirect in order to produce a label which can be addressed.
*/

/* Configurable variables - see ker / conf / console / Space.c */
extern int 	vga_count;
extern int 	mono_count;
extern int 	kb_lang;
extern int 	sep_shift;

HWentry	VTVGA =		{ 4, 0, VT_VGAPORT, { 0, VT_VGABASE }, { 25, 80 } };
HWentry	VTMONO =	{ 4, 0, VT_MONOPORT, { 0, VT_MONOBASE }, { 25, 80 } };

HWentry	* vtHWtable [] = {
	& VTVGA,	/* VGA followed by MONO is compatible to DOS */
	& VTMONO
};
#define	vtHWend		(vtHWtable + __ARRAY_LENGTH (vtHWtable))

extern	int	vtmminit ();

static	VTDATA	const_vtdata	= {
	vtmminit,		/* func */
	0,			/* port */
	0,			/* seg */
	0,			/* off */
	0, 0,			/* rowl, col */
	0,			/* pos */
	0x07,			/* attr */
	'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 	/* args */
	0,			/* nargs */
	0, 24, 25,		/* brow, erow, lrow */
	0, 0,			/* srow, scol */
	0, 24,			/* ibrow, ierow */
	0,			/* invis */
	0,			/* slow */
	1,			/* wrap */
	0x07,			/* oattr */
	0,			/* font */
	0,			/* esc */
	0			/* visible */
};

/* later this should be dynamic */
VTDATA	* vtconsole, ** vtdata;

int	vtcount, vtmax;
extern	int	vtactive;
int	vt_verbose = { 0 };
int	vt_opened = { 0 };

/* Terminal structure. */
TTY	** vttty;

/**************** State variables / Patchables ****************************/

int		islock;			/* Keyboard locked flag */
int		isbusy = 0;		/* Raw input conversion busy */
int		isvtbusy = 0;		/* VT switching busy (deferred) */
int		isvtnotdone = 0;	/* VT deferred not done */
int 		isturbo = 0;		/* Flag indicating turbo machine. */
static unsigned	shift;			/* Overall shift state */
static	char	scrollkb;		/* Scroll lock state */
static  char	lshiftkb = LSHIFT;	/* Left shift alternate state */
static	char	isfbuf [NFBUF];		/* Function key values */
static	char	* isfval [NFKEY];		/* Function key string pointers */
static	int	ledcmd;			/* LED update command count */
static	int	extended;		/* extended key scan count */
static	char	extmode;		/* use extended mode for this key */
static	char	ext0seen;		/* 0xE0 prefix seen */
static	char	fk_loaded;		/* true == funcion keys resident */
static	int	xlate = 1;		/* scan code translation flag */
static 	TIM	tp;			/* X thingamabob */
static	int	X11led;			/* Other X thingamabob */
static	silo_t	in_silo;		/* Used by character silo */
static	silo_t	vt_silo;		/* Queue of vt switches */

static int	kb_in_byte;

static unsigned char * lmaptab, * umaptab, * smaptab, * agmaptab;


/************************* Code *****************************************/

void
vtdeactivate (vp_new, vp_old)
VTDATA	* vp_new, * vp_old;
{
	int i;
	VTDATA	* vpi;

	/*
	 * if changing to another screen on same video board
	 *	for all screens on same board as new screen
	 *		deactivate, but don't update
	 * else - changing to a screen on different board
	 *	for all screens NOT on same board as new screen
	 *		deactivate, but don't update
	 */

	if (vp_old->vmm_port != vp_new->vmm_port) {
		T_CON (8, printf ("deactivate %x->%x ",
		  vp_old->vmm_port, vp_new->vmm_port));
		for (i = 0; i < vtcount; ++ i) {
			vpi = vtdata [i];
			if (vpi->vmm_port != vp_new->vmm_port &&
			    vpi->vmm_invis == 0) {
				/* update, but don't deactivate */
				vpi->vmm_invis = -1; 
				vtupdscreen (i);
				vpi->vmm_invis = 0; 
			}
		}
	}
}


void
vtactivate (vp)
VTDATA * vp;
{
	VTDATA	* vpi;
	int	i;

	/*
	 * If new active screen isn't visible, find currently visible
	 * screen and save to nonvideo memory, then restore new active
	 * screen from nonvideo.
	 */
	if (vp->vmm_visible == VNKB_FALSE) {
		for (i = 0 ; i < vtcount ; ++ i) {
			vpi = vtdata [i];

			if (vpi->vmm_port == vp->vmm_port
			  && vpi->vmm_visible == VNKB_TRUE) {
				ffcopy (vpi->vmm_voff, vpi->vmm_vseg,
					vpi->vmm_moff, vpi->vmm_mseg, TEXTBLOCK);
				break;
			}
		}
		ffcopy (vp->vmm_moff, vp->vmm_mseg,
			vp->vmm_voff, vp->vmm_vseg, TEXTBLOCK);
	}

	for (i = 0; i < vtcount; ++ i) {
		vpi = vtdata [i];
		if (vpi->vmm_port == vp->vmm_port) {
			vpi->vmm_visible = VNKB_FALSE;
			vpi->vmm_seg = vpi->vmm_mseg;
			vpi->vmm_off = vpi->vmm_moff;
			if (vpi->vmm_seg == 0)
				printf ("[2]vpi->vmm_seg = 0\n");
			PRINTV ("vt.back seg %x off %x\n",
				vpi->vmm_seg, vpi->vmm_off);
		}		
	}

	/*
	 * Set new active terminal
	 */
	vp->vmm_visible = VNKB_TRUE;
	vp->vmm_seg = vp->vmm_vseg;
	vp->vmm_off = vp->vmm_voff;
	if (vp->vmm_seg == 0)
		printf ("vp->vmm_seg = 0\n");
}


/*
 * update the keyboard status LEDS
 */

void
updleds ()
{
	int	s;

	s = sphi ();
	outb (KBDATA, LEDCMD);
       	ledcmd ++;
	spl (s);
}


/*
 * update the terminal to match vtactive
 */

void
updterminal (index)
int index;
{
	vtupdscreen (index);

	if (sep_shift)
		updleds ();
}


/*
 *
 * void
 * isvtswitch ()	-- deferred virtual terminal switch
 *
 *	Action: - save current shift key status
 *		- determine new active virtual terminal
 *		- deactivate shift key status of the current virtual terminal
 *		- deactivate current virtual terminal
 *		- activate shift key status of the new virtual terminal with 
 *		  the previously saved shift key status
 *		- activate new virtual terminal 
 *
 *	Notes:	isvtswitch () was scheduled as a deferred process by 
 *	process_key () which is a function called by vtkbintr ().
 */

void
isvtswitch (dummy)
int dummy;
{
	int		key_val;
	int		new_index, i;
	unsigned	lockshift, nolockshift; 
	VTDATA		* vp = vtdata [vtactive];
	VTDATA		* vp_old, * vp_new;
	static int	vtprevious;
	int		s;

	/*
 	 * When this is zero, queue_vt_switch () will crank off another
	 * deferred function
	 */

	isvtbusy = 0;

	/*
	 * Process the whole queue
	 */

	while (vt_silo.si_ix != vt_silo.si_ox) {

	if (sep_shift) {
		lockshift = shift & (CPLS | NMLS);
		nolockshift = shift & ~(CPLS | NMLS);
	} else {
		lockshift = 0;
		nolockshift = shift;
	}

		/*
		 * We must lock on the manipulation of these variables
		 * or we lose some vt switches.  Trust me -- it happens.
		 */

		s = sphi ();
		key_val = vt_silo.si_buf [vt_silo.si_ox];

		if (vt_silo.si_ox >= sizeof (vt_silo.si_buf) - 1)
			vt_silo.si_ox = 0;
		else
			vt_silo.si_ox ++;
		spl (s);

		PRINTV ("F%d: %d", key_val, vtactive);


		switch (key_val) {

		case VTKEY_HOME:
			new_index = 0;
			break;

		case VTKEY_NEXT:
			new_index = vtactive;
			for ( i = 0; i < vtcount; ++ i ) {
				new_index = ++ new_index % vtcount;
				if (vttty [new_index]->t_open)
					break;
			}
			break;

		case VTKEY_PREV:
			new_index = vtactive;
			for ( i = 0; i < vtcount; ++ i ) {
				new_index = (--new_index + vtcount) % vtcount;
				if ( vttty [new_index]->t_open )
					break;
			}
			break;

		case VTKEY_TOGL:
			new_index = vtprevious;
			break;

		default:
			new_index = vtindex (vtkey_to_dev (key_val));
			if ( new_index < 0) {
				putchar ('\a');
				return;
			}
		}

		T_CON (8, printf ("%d->%d ", vtactive, new_index));

		if (new_index == vtactive)
			return;

		/* Save which locking shift states are in effect. */

		s = sphi ();
		vp_old = vtdata [vtactive];
		vp_new = vtdata [new_index];

		vp_old->vnkb_shift = lockshift;
		vtdeactivate (vp_new, vp_old);	/* deactivate old virtual terminal */

		/* Restore shift lock state, append current momentary shift state. */
		shift = vp_new->vnkb_shift | nolockshift;
		vtactivate (vp_new);		/* activate new virtual terminal */
		updterminal (new_index);
		vtprevious = vtactive;
		vtactive = new_index;		/* update vtactive */
		spl (s);
	}
	isvtnotdone = 0;
}


/*
 * This builds the queue of vt switches so they may be done as
 * a deferred function.  This had to be done since re-enabling a
 * virtual term was slow enough that if vt's were switched rapidly,
 * the deferred queue overflowed and things locked up.
 *
 * There is a small chance of a race condition about the variabl
 * isvtbusy, but this has been minimized through the use of a lock
 * variable in isvtswitch.
 */

static void
queue_vt_switch (vt_key)
char vt_key;
{
	vt_silo.si_buf [vt_silo.si_ix] = vt_key;

	if (++ vt_silo.si_ix >= sizeof (vt_silo.si_buf))
		vt_silo.si_ix = 0;

	if (! isvtbusy) {
		isvtbusy = 1;
		defer (isvtswitch, 0);
	}
}


void
vtdatainit (vp)
VTDATA	* vp;
{
	/*
	 * vtdata init - vmm part
	 */
	vp->vmm_invis = 0;		/* cursor visible */

	vp->vt_buffer = kalloc (TEXTBLOCK);
	vp->vmm_seg = vp->vmm_mseg = vtds_sel ();
	vp->vmm_off = vp->vmm_moff = vp->vt_buffer;
	PRINTV ("vt@%x init index %d,%d), seg %x, off %x\n",
		vp, vp->vt_ind, vp->vmm_mseg, vp->vmm_moff);

	/*
	 * vtdata init - vnkb part
	 */

	/* Make the first memory block active, if present */ 
	vp->vnkb_lastc = 0;
	vp->vnkb_fnkeys = 0;	
	vp->vnkb_funkeyp = 0;	
	vp->vnkb_fk_loaded = 0;			/* no Fn keys yet */
}


/*
 * Load entry point.
 *  Do reset the keyboard because it gets terribly munged
 *  if you type during the boot.
 */

void
isload ()
{
	short 		i;	/* was: int i */
 	HWentry 	** hw;
 	VTDATA 	* vp;

	/* Use stune et al to adjust vga_count and mono_count. */
	VTVGA.count = vga_count;
	VTMONO.count = mono_count;

	/*
	 * Set up keyboard tables
	 */

	switch (kb_lang) {
		case kb_lang_fr:
			agmaptab = fr_agmaptab;
			lmaptab = fr_lmaptab;
			umaptab = fr_umaptab;
			smaptab = fr_de_smaptab;
			break;
		case kb_lang_de:
			agmaptab = de_agmaptab;
			lmaptab = de_lmaptab;
			umaptab = de_umaptab;
			smaptab = fr_de_smaptab;
			break;
		default:
			agmaptab = 0;
			lmaptab = us_lmaptab;
			umaptab = us_umaptab;
			smaptab = us_smaptab;
			break;
	} /* switch */

	/*
	 * Reset keyboard if NOT an XT turbo.
	 */

	if (! isturbo) {
		outb (KBCTRL, 0x0C);		/* Clock low */
		for (i = 10582; --i >= 0; );	/* For 20ms */
		outb (KBCTRL, 0xCC);		/* Clock high */
		for (i = 0; --i != 0; )
			;
		i = inb (KBDATA);
		outb (KBCTRL, 0xCC);			/* Clear keyboard */
		outb (KBCTRL, 0x4D); 			/* Enable keyboard */
	}

	PRINTV ("vtload:\n");
	fk_loaded = 0;

	/* figure out what our current max is */
	for (vtmax = 0, hw = vtHWtable ; hw != vtHWend ; hw ++) {
		vtmax += (* hw)->count;
		(* hw)->found = 0;	/* assume non-exist */
	}
	PRINTV ("vtload: %d screens possible\n", vtmax);

	vtdata = (VTDATA **) kalloc (vtmax * sizeof (* vtdata));
	if (vtdata == NULL) {
		printf ("vtload: unable to obtain vtdata [%d]\n", vtmax);
		return;
	}

	PRINTV ( "vtload: obtained vtdata [%d] @%x\n", vtmax, vtdata );

	vttty = (TTY **) kalloc (vtmax * sizeof (* vttty));
	if (vttty == NULL) {
		printf ("vtload: unable to obtain vttty [%d]\n", vtmax);
		return;
	}

	PRINTV ( "vtload: obtained vttty [%d] @%x\n", vtmax, vttty );

	/* determine which video adaptors are present */

	for (vtcount = 0, hw = vtHWtable ; hw != vtHWend ; hw ++) {
		/* remember our logical start */
		(* hw)->start = vtcount;
		PRINTV (", start %d\n", vtcount);

		/* allocate the necessary memory */
		for (i = 0; i < (* hw)->count; ++ i) {
			vp = vtdata [vtcount] = kalloc (sizeof (VTDATA));
			PRINTV ( "     vtdata [%d] = @%x\n", vtcount, vp );
			if (vp == NULL || ! VTttyinit (vtcount)) {
				printf ("not enough memory for VTDATA\n" );
				return;
			}

			/* fill in appropriately */
			* vp = const_vtdata;
			vp->vmm_port = (* hw)->port;
			vp->vmm_vseg = (* hw)->vidmemory.seg;
			vp->vmm_voff = (* hw)->vidmemory.off;

			vp->vt_ind = vtcount;
			vtdatainit (vp);
			if (i == 0) {
				vp->vmm_visible = VNKB_TRUE;
				vp->vmm_seg = vp->vmm_vseg;
				vp->vmm_off = vp->vmm_voff;
				vtupdscreen (vtcount);
			}
			(* hw)->found ++;
			vtcount ++;
		}
	}

	/*
	 * initialize vtconsole
	 */

	vtconsole = vtdata [vtactive = 0];
	vtconsole->vmm_invis = 0;		/* vtconsole cursor visible */

	/*
	 * Enable vtmmwatch () invocation every second.
	 */

	drvl [VT_MAJOR].d_time = 1;

	/*
	 * Initialize video display.
	 */

	for (i = 0 ; i < vtcount ; ++ i)
		vtmmstart (vttty [i]);
}


/*
 * Unload entry point.
 */

void
isuload ()
{
	/* Restore pointers to original state. */
	vtconsole = vtdata [0];
	vtconsole->vmm_invis = 0;
	vtconsole->vmm_visible = VNKB_TRUE;

	if (vt_opened)
		printf ("VTclose with %d open screens\n", vt_opened);

}


/* Init function keys */

void
initkeys ()
{
	int i;
	char * cp1, * cp2;

	for (i = 0; i < NFKEY ; i ++)
		isfval [i] = 0; 	/* clear function key buffer */
	cp2 = isfbuf;			/* pointer to key buffer */

	for (i = 0 ; i < NFKEY ; i ++) {
		isfval [i] = cp2;	/* save pointer to key string */
		cp1 = deffuncs [i];	/* get init string pointer */
		while ((* cp2 ++ = * cp1 ++) != -1) 	/* copy key data */
			if (cp2 >= isfbuf + NFBUF - 3)	/* overflow? */
				return;
	}
}


/*
 * Open routine.
 */

void
isopen (dev, mode)
dev_t dev;
unsigned int mode;
{
	int s;
	TTY * tp;
	int	index = vtindex (dev);

	PRINTV ("isopen: %x\n", dev);
	if (index < 0 || index >= vtcount) {
		set_user_error (ENXIO);
		return;
	}

	tp = vttty [index];
	if ((tp->t_flags & T_EXCL) != 0 && ! super ()) {
		set_user_error (ENODEV);
		return;
	}
	ttsetgrp (tp, dev, mode);

	s = sphi ();
	if (tp->t_open ++ == 0) {
	  	initkeys ();		/* init function keys */
	   	tp->t_flags = T_CARR;  /* indicate "carrier" */
	   	ttopen (tp);
	}
	spl (s);
}


/*
 * Close a tty.
 */

void
isclose (dev)
{
	TTY * tp = vttty [vtindex (dev)];

	if (-- tp->t_open == 0)
		ttclose (tp);

}


/*
 * Read routine.
 */

void
isread (dev, iop)
dev_t dev;
IO * iop;
{
	TTY * tp = vttty [vtindex (dev)];

	ttread (tp, iop, 0);
	if (tp->t_oq.cq_cc)
		vtmmtime (tp);
}


void
kbstate (action)
int action;
{
	if (action == 1) {
		timeout (& tp, 20, kbstate, 2);
		outb (KBCTRL, 0xCC);		/* Clock high */
	}

	if (action == 2) {
		int i = inb (KBDATA);
		outb (KBCTRL, 0xCC);		/* Clear keyboard */
		outb (KBCTRL, 0x4D);		/* Enable keyboard */
	}
}


/*
 * Set and receive the function keys.
 */

void
isfunction (c, v)
int c;
char * v;
{
	char * cp;
	int i;

	if (c == TIOCGETF) {
		for (cp = isfbuf; cp < & isfbuf [NFBUF]; cp ++)
		    putubd (v ++, * cp);
	} else {
		for (i = 0 ; i < NFKEY ; i ++)	/* zap current settings */
			isfval [i] = 0;
		cp = isfbuf;			/* pointer to key buffer */
		for (i = 0 ; i < NFKEY ; i ++) {
			isfval [i] = cp;        /* save pointer to key string */
			while ((* cp ++ = getubd (v ++)) != -1)  /* copy key data */
				if (cp >= isfbuf + NFBUF - 3)  /* overflow? */
					return;
		}
	}
}


/*
 * Ioctl routine.
 */

void
isioctl (dev, com, vec)
dev_t dev;
struct sgttyb * vec;
{
	int s;

	switch (com) {
#define KDDEBUG 0
#if KDDEBUG
	case KDMEMDISP: {
		struct kd_memloc * mem;
		unsigned char ub, pb;
		mem = (struct kd_memloc *) vec;
		pxcopy (mem->physaddr, & pb, 1, SEL_386_KD);
		ub = getubd (mem->vaddr);
		printf ("User's byte %x (%x), Physical byte %x, Addresses %x %x\n",
			mem->ioflg, ub, pb, mem->vaddr, mem->physaddr);
		break;
	}
#endif
	case KDMAPDISP: {
		struct kd_memloc * mem;
		mem = (struct kd_memloc *) vec;
		mapPhysUser (mem->vaddr, mem->physaddr, mem->length);
		break;
	}

	case KDDISABIO:
		__kddisabio();
		break;

	case KDENABIO:
		__kdenabio();
		break;

	case KDADDIO:
		__kdaddio((unsigned short)vec);
		break;

	case KDDELIO:
		__kddelio((unsigned short)vec);
		break;

	case KIOCSOUND: {
		if (vec) {
			outb (TIMER_CTL, 0xB6); 
			outb (TIMER_CNT, (int)vec & 0xFF);
			outb (TIMER_CNT, (int)vec >> 8);
			/* Turn speaker on */
			outb (SPEAKER_CTL, inb (SPEAKER_CTL) | 03);
		} else 
			outb (SPEAKER_CTL, inb (SPEAKER_CTL) & ~ 03 );
		break;
	}

	case KDSKBMODE: {
		outb (KBCTRL, 0x0C);		/* Clock low */
		timeout (& tp, 3, kbstate, 1);	/* wait about 20-30ms */
		xlate = (int)vec;
		break;
	}

	case KDGKBSTATE: 
		* (char *) vec = '\x00';
		if (shift & SES)
			* (char *) vec |= M_KDGKBSTATE_SHIFT;
		if (shift & CTS)
			* (char *) vec |= M_KDGKBSTATE_CTRL;
		if (shift & ALS)
			* (char *) vec |= M_KDGKBSTATE_ALT;
		break;

	case KDSETLED: {
		X11led = (int)vec;
		updleds ();
		break;
	}

	case KDGETLED:
		* (char *) vec = 0;
		if (shift & NMLS)
			* (char *) vec |= M_KDGETLED_NUMLOCK;
		if (shift & CPLS)
			* (char *) vec |= M_KDGETLED_CAPLOCK;
		if (scrollkb & 1)
			* (char *) vec |= M_KDGETLED_SCRLOCK;
		break;

	case TIOCSETF:
	case TIOCGETF:
		isfunction (com, (char *)vec);
		break;

	case TIOCSHIFT:   /* switch left-SHIFT and "\" */
		lshiftkb = LSHIFTA;    /* alternate values */
		lmaptab [41] = '\\';
		lmaptab [42] = XXX;
		umaptab [41] = '|';
		umaptab [42] = XXX;
		smaptab [41] = SS1;
		smaptab [42] = SHFT;
		break;

	case TIOCCSHIFT:  /* normal (default) left-SHIFT and "\" */
		lshiftkb = LSHIFT;     /* normal values */
		lmaptab [41] = XXX;
		lmaptab [42] = '\\';
		umaptab [41] = XXX;
		umaptab [42] = '|';
		smaptab [41] = SHFT;
		smaptab [42] = SS1;
		break;

	  case KIOCINFO:
	        * (int *) vec = 0x6664;
	        break;

	/* Don't squawk if they try to load tables. */
	case TIOCSETKBT:
	        break;

	default:
		s = sphi ();
		ttioctl (vttty [vtindex (dev)], com, vec);
		spl (s);
		break;
	}
}


/*
 * Poll routine.
 */

int
ispoll (dev, ev, msec)
dev_t dev;
int ev;
int msec;
{
	return ttpoll (vttty [vtindex (dev)], ev, msec);
}


/*
 * Process numeric keypad for virtual terminals.
 */

void
vtnumeric (c)
int	c;
{
	switch (c) {
	case 71:			/* ctrl-7 */
		queue_vt_switch (vt7);
		break;

	case 72:			/* ctrl-8 */
		queue_vt_switch (vt8);
		break;

	case 73:			/* ctrl-9 */
		queue_vt_switch (vt9);
		break;

	case 74:			/* ctrl - */
		queue_vt_switch (vtp);
		break;

	case 75: 
	        queue_vt_switch (vt4);
	        break;

	case 76:
	        queue_vt_switch (vt5);
	        break;

	case 77:	/* ctrl 4/5/6 (vt5, vt6, vt7) */
		queue_vt_switch (vt6);
		break;

	case 78:			/* ctrl + */
		queue_vt_switch (vtn);
		break;

	case 79:			/* ctrl-1 */
		queue_vt_switch (vt1);
		break;

	case 80:			/* ctrl-2 */
		queue_vt_switch (vt2);
		break;

	case 81:			/* ctrl-3 */
		queue_vt_switch (vt3);
		break;

	case 82: 			/* ctrl 0  (vt0) */
		queue_vt_switch (vt0);
		break;

	case 83:			/* ctrl del (toggle) */
		c = vtt;
		queue_vt_switch (vtt);
		break;
	}
}


/**
 *
 * void
 * isin ( c )	-- append character to raw input silo
 * char c;
 */

static void
isin (c)
int c;
{
	int cache_it = 1;
	TTY * tp = vttty [vtactive];

	/*
	 * If using software incoming flow control, process and
	 * discard t_stopc and t_startc.
	 */
	if (_IS_IXON_MODE (tp)) {
		if (_IS_START_CHAR (tp, c) ||
		    (_IS_IXANY_MODE (tp) && (tp->t_flags & T_STOP) != 0)) {
			tp->t_flags &= ~ (T_STOP | T_XSTOP);
			ttstart (tp);
			cache_it = 0;
		} else if (_IS_STOP_CHAR (tp, c)) {
			if ((tp->t_flags & T_STOP) == 0)
				tp->t_flags |= (T_STOP | T_XSTOP);
			cache_it = 0;
		}
	}

	/*
	 * If the tty is not open the character is
	 * just tossed away.
	 */

	if (vttty [vtactive]->t_open == 0)
		return;

	/*
	 * Cache received character.
	 */
	if (cache_it) {
		in_silo.si_buf [ in_silo.si_ix ] = c;

		if ( ++ in_silo.si_ix >= sizeof (in_silo.si_buf) )
			in_silo.si_ix = 0;

	}
}


/*
 * Handle special input sequences.
 * The character passed is the key number.
 */

int
isspecial (c)
int c;
{
	char * cp;
	int s;
	int	update_leds = 0;

	cp = 0;

	switch (c) {
	case 15:					/* cursor back tab */
		cp = ESCAPE_STRING "[Z";
		break;

	case 53:
		if (kb_lang == kb_lang_fr || kb_lang == kb_lang_de) {
			if (extmode)
				cp = "/";
			else 
				if (shift & SES)
					cp = "_";
				else
					cp = "-";
		}
		break;

	case 55:					/* ignore PrtScr */
		if (kb_lang == kb_lang_fr || kb_lang == kb_lang_de) {
			if (! extmode)
				cp = "*";
		}
		break;

	case 59: case 60: case 61: case 62: case 63:	/* Function keys */
	case 64: case 65: case 66: 
		/* offset to function string */
		/* Magic numbers 21 and 61 to mach vtnkb constants */

		if ( shift & ALS ) {
			switch (c) {
			case 59:	/* Alt-F1 */
				queue_vt_switch (vt0);
				break;

			case 60:	/* Alt-F2 */
				queue_vt_switch (vt1);
				break;

			case 61:	/* Alt-F3 */
				queue_vt_switch (vt2);
				break;

			case 62:	/* Alt-F4 */
				queue_vt_switch (vt3);
				break;

			case 63:	/* Alt-F5 */
				queue_vt_switch (vt4);
				break;

			case 64:	/* Alt-F6 */
				queue_vt_switch (vt5);
				break;

			case 65:	/* Alt-F7 */
				queue_vt_switch (vt6);
				break;

			case 66:	/* Alt-F8 */
				queue_vt_switch (vt7);
				break;

			default:
				break;
			}
		} else if ((shift & (SES)) && (shift & CTS)) /* ctrl-shft-Fx */
			cp = isfval [c - 29];
		else if (shift & CTS)			/* ctrl-Fx */
			cp = isfval [c - 39];
		else if (shift & (SES))		/* shift-Fx */
			cp = isfval [c - 49];
		else
			cp = isfval [c - 59];			/* Plain Fx */
		break;

	case 67: case 68:
		/* offset to function string */
		if ( shift & ALS )  {
			switch (c) {
			case 67:	/* Alt-F9 */
				queue_vt_switch (vt8);
				break;

			case 68:	/* Alt-F10 */
				queue_vt_switch (vt9);
				break;

			default:
				break;
			}
		} else if ((shift & (SES)) && (shift & CTS)) /* cs-Fx */
			cp = isfval [c-29];
		else if (shift & CTS)		/* c-Fx */
			cp = isfval [c-39];
		else if (shift & (SES))	/* s-Fx */
			cp = isfval [c-49];
		else
			 cp = isfval [c-59];		/* Fx */
		break;

	case 70:		/* Scroll Lock -- stop / start output */
	{
		static char cbuf [2];

		cp = cbuf;	/* working buffer */
		if ((vttty [vtactive]->t_sgttyb.sg_flags & RAWIN) != 0)
			break;

		/* not if in RAW mode */

		++ update_leds;
		if (vttty [vtactive]->t_flags & T_STOP){/* output stopped? */
			cbuf [0] = vttty [vtactive]->t_tchars.t_startc;  
			scrollkb = 0;
		} else {
			cbuf [0] = vttty [vtactive]->t_tchars.t_stopc;   
			scrollkb = 1;
		}
		break;
	}

	case 79:		/* 1/ End */
	case 80:		/* 2/ DOWN */
	case 81:		/* 3/ PgDn */
	case 82:		/* 0/ Ins */
	case 83:		/* ./ Del */
		-- c;		/* adjust code */
		/* FALL THROUGH */

	case 75:		/* 4/ LEFT */
	case 76:		/* 5 */
	case 77:		/* 6/ RIGHT */
		-- c;		/* adjust code */
		/* FALL THROUGH */

	case 71:		/* 7/ Home / Clear */
	case 72:		/* 8/ UP */
	case 73:		/* 9/ PgUp */
		s = 0;			/* start off with normal keypad */
		if (shift & NMLS)		/* num lock? */
			s = 1;		/* set shift pad */
		if (shift & SES)		/* shift? */
			s ^= 1;		/* toggle shift pad */
		if (shift & AKPS)		/* alternate pad? */
			s = 2;		/* set alternate pad */
		if (kb_lang == kb_lang_fr || kb_lang == kb_lang_de) {
			if (extmode)		/* not from keypad? */
				s = 0;		/* force normal sequence */
		}
		cp = keypad [c - 71][s];   /* get keypad value */
		break;
	}
	if (cp)					/* send string */
		while ((* cp != 0) && (* cp != -1))
			isin (* cp ++ & 0xFF);
	return update_leds;
}


/**
 *
 * void
 * ismmfunc ( c )	-- process keyboard related output escape sequences
 * char c;
 */

void
ismmfunc (c)
int c;
{
	switch (c) {
	case 't':	/* Enter numlock */
		shift |= NMLS;
		updleds ();			/* update LED status */
		break;

	case 'u':	/* Leave numlock */
		shift &= ~ NMLS;
		updleds ();			/* update LED status */
		break;

	case '=':	/* Enter alternate keypad */
		shift |= AKPS;
		break;

	case '>':	/* Exit alternate keypad */
		shift &= ~ AKPS;
		break;

	case 'c':	/* Reset terminal */
		islock = 0;
		shift  = 0;
		initkeys ();
		updleds ();			/* update LED status */
		break;
	}
}


/**
 *
 * void
 * isbatch ()	-- raw input conversion routine
 *
 *	Action:	Enable the video display.
 *		Canonize the raw input silo.
 *
 *	Notes:	isbatch () was scheduled as a deferred process by vtkbintr ().
 */

static void
isbatch (tp)
TTY * tp;
{
	int c;
	static int lastc;
	VTDATA		* vp = (VTDATA *) tp->t_ddp;
	int s;

	/*
	 * Ensure video display is enabled.
	 */
	if (vp->vmm_visible)
		vtmm_von (vp);

	isbusy = 0;

	/*
	 * Process all cached characters.
	 */
	while (in_silo.si_ix != in_silo.si_ox) {
		/*
		 * Get next cached char.
		 */

	        s = sphi ();
		c = in_silo.si_buf [in_silo.si_ox];

		if (in_silo.si_ox >= sizeof (in_silo.si_buf) - 1)
			in_silo.si_ox = 0;
		else
			in_silo.si_ox ++;
		spl (s);

		if (islock == 0 || _IS_INTERRUPT_CHAR (tp, c) ||
		    _IS_QUIT_CHAR (tp, c)) {
			ttin (tp, c);
		} else if (c == 'b' && lastc == ESCAPE_CHAR) {
			islock = 0;
			ttin (tp, lastc);
			ttin (tp, c);
		} else if (c == 'c' && lastc == ESCAPE_CHAR) {
			ttin (tp, lastc);
			ttin (tp, c);
		} else
			putchar ('\a');

		lastc = c;
	}
}


/*
 * unlock the scroll in case an interrupt character is received
 */

void
kbunscroll ()
{
	scrollkb = 0;
	updleds ();
}


int
VTttyinit (i)
int i;
{
	TTY * tp;

	/*
	 * get pointer to TTY structure from kernal memory space
	 */
	if ((tp = vttty [i] = (TTY *) kalloc (sizeof (TTY))) == NULL)
		return 0;
	PRINTV ("     vttty [%d]: @%x, ", i, tp);

	tp->t_param = NULL;
	tp->t_start = & vtmmstart;

	tp->t_ddp = (char *) vtdata [i];
	PRINTV ("data @%lx\n", tp->t_ddp);
	return 1;
}


/*
 * Given device number, return index for vtdata [], vttty [], etc.
 *
 * Major number must be VT_MAJOR for CPU to get here.
 *
 *      Minor Number	Index Value
 *	----- ------ 	----- -----  
 *	0000  0000	vtactive ... device (2, 0) is the active screen
 *	0000  0001	0
 *	0000  0010	1
 *	0000  0011	2
 *	   ....
 *	0000  1111	14
 *
 *	0100  xxxx	xxxx ... color devices only
 *	0101  xxxx	xxxx - (# of color devices found) ... monochrome only
 *
 * Return value is in range 0 to vtcount-1 for valid minor numbers,
 * -1 for invalid minor numbers.
 */

int
vtindex (dev)
dev_t dev;
{
	int	ret = -1;

	if ( dev & VT_PHYSICAL ) {
		int	hw = ( dev >> 4 ) & 3;
		int	hw_index = dev & 0x0F;

		if ( hw_index < vtHWtable [hw]->found )
			ret = vtHWtable [hw]->start + hw_index;
	} else {
		int	lg_index = dev & 0x0F;

		if (lg_index == 0)
			ret = vtactive;
		if (lg_index > 0 && lg_index <= vtcount ) 
			ret = lg_index-1;
	}
	if (ret >= 0)
		ret %= vtcount;
	else
		PRINTV ( "vtindex: (%x) %d. invalid !\n", dev, ret );
	return ret;
}


/*
 * Given a function key number (e.g. vt0),
 * return the corresponding minor device number.
 *
 * Assume valid key number (VTKEY (fnum) is true) by the time we get here.
 */

int
vtkey_to_dev (fnum)
int fnum;
{
	if (fnum >= vt0 && fnum <= vt15)
		return fnum - vt0 + 1;
	if (fnum >= color0 && fnum <= color15)
		return (fnum - color0) | (VT_PHYSICAL | VT_HW_COLOR);
	if (fnum >= mono0 && fnum <= mono15)
		return (fnum - mono0) | (VT_PHYSICAL | VT_HW_MONO);

	printf ("vtkey_to_dev (%d)! ", fnum);
	return 0;
}


/*
 * Receive interrupt.
 */

void
vtkbintr ()
{
	int	c;
	int	s;
	int	r;
	int	savests;
	int	update_leds = 0;
	int	i;

	if (isbusy == 0) {
		isbusy = 1;
		defer (isbatch, vttty [vtactive]);
	}

	
	/*
	 * Pull character from the data
	 * port. Pulse the KBFLAG in the control
	 * port to reset the data buffer.
	 */

	r = inb (KBDATA) & 0xFF;
	c = inb (KBCTRL);
	outb (KBCTRL, c | KBFLAG);
	outb (KBCTRL, c);

	if (! xlate) {
		if (ledcmd) {
			if (r == KBACK) {		/* output to status LEDS */
				ledcmd --;
				outb (KBDATA, X11led);
				return;
			}
		}
		isin (r);
		return;
	}

#if	KBDEBUG
	printf ("kbd: %d\n", r);			/* print scan code / direction */
#endif
	if (ledcmd) {
		if (r == KBACK) {		/* output to status LEDS */
		        ledcmd --;

			 /*
			  * This is a stupid delay for a stupid way
			  * of doing things.  Timing constraints between
			  * an ACK receive and a sending of data should
			  * have been implemented, so now we suffer.
			  */

			busyWait2(0, 2500);
			c = scrollkb & 1;
			if (shift & NMLS)
				c |= 2;
			if (shift & CPLS)
				c |= 4;
			outb (KBDATA, c);
		}
		return;
	}

	if (extended > 0) {			/* if multi-character seq, */
		-- extended;			/* ... ignore this char */
		return;
	}

	switch (r) {
	case EXTENDED0:				/* 0xE0 prefix found */
		if (kb_lang == kb_lang_fr || kb_lang == kb_lang_de) {
			ext0seen = 1;
			return;
		}
		break;

	case EXTENDED1:				/* ignore extended sequences */
		extended = 5;
		return;

	case 0xFF:				/* Overrun */
		return;
	}

	if (kb_lang == kb_lang_fr || kb_lang == kb_lang_de) {
		if (ext0seen) {
			ext0seen = 0;
			extmode = 1;
		} else 
			extmode = 0;
	}

	c = (r & KEYSC) - 1;

#if	0
	/*
	 * Check for reset.
	 */

	if ((r & KEYUP) == 0 && c == DELETE &&
	    (shift & (CTS | ALS)) == (CTS | ALS))
		boot ();
#endif

	/*
	 * Track "shift" keys.
	 */

	s = smaptab [c];
	if (s & SHFT) {
		if (r & KEYUP) {			/* "shift" released */
			if (c == RSHIFT)
				shift &= ~ SRS;
			else if (c == lshiftkb)
				shift &= ~ SLS;
			else if (c == CTRLkb)
				shift &= ~ CTS;
			else if (c == ALTkb) {
				if (kb_lang == kb_lang_fr ||
				    kb_lang == kb_lang_de)
					shift &= extmode ? ~ AGS : ~ ALS;
				else
					shift &= ~ ALS;
			}
		} else {			/* "shift" pressed */
			if (c == lshiftkb)
				shift |= SLS;
			else if (c == RSHIFT)
				shift |= SRS;
			else if (c == CTRLkb)
				shift |= CTS;
			else if (c == ALTkb) {
				if (kb_lang == kb_lang_fr ||
				    kb_lang == kb_lang_de)
					shift |= extmode ? AGS : ALS;
				else
					shift |= ALS;
			} else if (c == CAPLOCK) {
				shift ^= CPLS;	/* toggle cap lock */
				updleds ();
			} else if (c == NUMLOCK) {
				shift ^= NMLS;	/* toggle num lock */
				updleds ();
			}
		}
		return;
	}

	/*
	 * No other key up codes of interest.
	 */
	if (r & KEYUP)
		return;

	/*
	 * Map character, based on the
	 * current state of the shift, control, alt graphics,
	 * meta (ALT) and lock flags.
	 */
	if ((shift & AGS) &&  /* Alt Graphics ? */
	    (kb_lang == kb_lang_fr || kb_lang == kb_lang_de))
		c = agmaptab [c];
	else if (shift & CTS) {
		if (s == CTS)			/* Map Ctrl (BS | NL) */
			c = (c == BACKSP) ? 0x7F : 0x0A;
		else if (s == SS1 || s == LET) {
			if ((c = umaptab [c]) != SPC)	/* Normal Ctrl map */
				c &= 0x1F;	/* Clear bits 5-6 */
		} else {
			if (s == KEY || s == SS0) 
				vtnumeric (r);
			return;			/* Ignore this char */
		}
	} else if (s &= shift) {
		if (shift & SES) {		/* if shift on */
			if (s & (CPLS | NMLS))  /* if caps / num lock */
				c = lmaptab [c];/* use unshifted */
			else 
				c = umaptab [c];/* use shifted */
			
		} else {			/* if shift not on */
			if (s & (CPLS | NMLS))	/* if caps / num lock */
				c = umaptab [c];/* use shifted */
			else
				c = lmaptab [c]; /* use unshifted */
		}
	} else
		c = lmaptab [c];		 /* use unshifted */

	/*
	 * Act on character.
	 */
	if (c == XXX)
		return;				 /* char to ignore */

	if (c != SPC) {			 /* not special char? */
		if (shift & ALS)	 /* ALT (meta bit)? */
			c |= 0x80;	 /* set meta */
		isin (c);		 /* send the char */
	} else
		update_leds += isspecial (r);	 /* special chars */

	if (update_leds) {
		savests = sphi ();
		outb (KBDATA, LEDCMD);
		ledcmd ++;
		spl (savests);
	}
}


CON vtkbcon = {
	DFCHR | DFPOL,			/* Flags */
	KB_MAJOR,			/* Major index */
	isopen,				/* Open */
	isclose,			/* Close */
	NULL,				/* Block */
	isread,				/* Read */
	vtmmwrite,			/* Write */
	isioctl,			/* Ioctl */
	NULL,				/* Powerfail */
	vtmmwatch,			/* Timeout */
	isload,				/* Load */
	isuload,			/* Unload */
	ispoll				/* Poll */
};