#include "insignia.h" 
#include "host_def.h"
/*
 * SoftPC Version 2.0
 *
 * Title:	keyba.c
 *
 * Description:	AT keyboard Adaptor I/O functions.
 *		
 *		kbd_inb(port,val)
 *		int port;
 *		half_word *val;
 *				provides the next scan code from the 
 *				keyboard controller (8042), or the 
 *				status byte of the controller, depending
 *				on the port accessed.
 *		kbd_outb(port,val)
 *		int port;
 *		half_word val;
 *				Sends a byte to the controller or the
 *				keyboard processor (6805), depending on
 *				the port accessed.
 *		AT_kbd_init()
 *				Performs any initialisation of the
 *				keyboard code necessary.
 *
 *		The system presents an interface to the host environment
 *		which is provided with the calls:
 *
 *		host_key_down(key)
 *		int key;
 *		host_key_up(key)
 *		int key;
 *
 *		These routines provide the keyboard code with information
 *		on the events which occur on the host keyboard. The key codes
 *		are the key numbers as given in the XT286 Technical Manual.
 *
 * Author:	William Charnell
 *
 * Notes:	
 *
 */


#ifdef SCCSID
static char SccsID[]="@(#)keyba.c	1.41 11/10/92 Copyright Insignia Solutions Ltd.";
#endif

#ifdef SEGMENTATION
/*
 * The following #include specifies the code segment into which this
 * module will by placed by the MPW C compiler on the Mac II running
 * MultiFinder.
 */
#include "SOFTPC_PPI.seg"
#endif


/*
 *    O/S include files.
 */
#include <stdio.h>
#include <sys/types.h>
#include <time.h>

/*
 * SoftPC include files
 */
#include "xt.h"
#include "cpu.h"
#include "sas.h"
#include "ios.h"
#include "ppi.h"
#include "timeval.h"
#include "timer.h"
#include "keyboard.h"
#include "error.h"
#include "config.h"
#include "ica.h"
#include "keyba.h"
#include "quick_ev.h"
#ifdef macintosh
#include "ckmalloc.h"
#endif /* macintosh */

#include "debug.h"


#ifdef NTVDM
#include "idetect.h"
#include "nt_eoi.h"

/* exported for NT host event code */
VOID KbdResume(VOID);
BOOL bPifFastPaste=TRUE;

/* imported from NT host code */
IMPORT ULONG  WaitKbdHdw(ULONG dwTimeOut);
IMPORT ULONG  KbdHdwFull;
IMPORT VOID   HostReleaseKbd(VOID);
IMPORT VOID   HostResetKbdNotFullEvent(VOID);
IMPORT VOID   HostSetKbdNotFullEvent(VOID);


/* imported from keybd_io.c */
IMPORT int bios_buffer_size(void);
IMPORT BOOL bBiosOwnsKbdHdw;  // our kbd bios code owns the Keyboard Mutex
word KbdInt09Seg;
word KbdInt09Off;

#undef LOCAL
#define LOCAL

// local state variables for kbd interrupt regulation
VOID KbdIntDelay(VOID);
BOOL bBiosBufferSpace = TRUE;
BOOL bKbdIntHooked = FALSE;
char KbdData = -1;
BOOL bKbdEoiPending = TRUE;   // Kbd interrupts blocked until KbdResume invoked
BOOL bDelayIntPending = FALSE;
BOOL bForceDelayInts = FALSE;
BOOL bKbdNotFullReset = FALSE;
ULONG LastKbdInt=0;

#endif  /* NTVDM */



#define NUM_LOCK_ADD_ARRAY 127
#define L_SHIFT_ADD_ARRAY 128
#define R_SHIFT_ADD_ARRAY 129
#define CASE_4_SHIFTED_ARRAY 130
#define ALT_CASE_4_ARRAY 131
#define CASE_5_CTRLED_ARRAY 132

#define NUM_LOCK_ADD 7
#define L_SHIFT_ADD 8
#define R_SHIFT_ADD 9
#define CASE_4_SHIFTED 10
#define ALT_CASE_4 11
#define CASE_5_CTRLED 12

#define KEYBOARD_INT_ADAPTER 0
#define KEYBOARD_INT_LINE 1
#define BASE_DELAY_UNIT 5
#define DEFAULT_REPEAT_TARGET 1

#define SET_3_KEY_TYPE_SET_SEQUENCE 1
#define SET_STATUS_INDICATORS_SEQUENCE 2
#define SET_RATE_DELAY_SEQUENCE 3
#define SCAN_CODE_CHANGE_SEQUENCE 4

#define WRITE_8042_CMD_BYTE_SEQUENCE 1
#define WRITE_8042_OUTPUT_PORT_SEQUENCE 2

#define KEY_DOWN_EVENT 1
#define KEY_UP_EVENT 2

#define DEFAULT_SCAN_CODE_SET 2

#ifdef REAL_KBD
extern void send_to_real_kbd();
extern void wait_for_ack_from_kb();
#endif

/*
 * Globally available function pointers
 */
GLOBAL VOID ( *host_key_down_fn_ptr )();
GLOBAL VOID ( *host_key_up_fn_ptr )();

#ifndef NTVDM
GLOBAL VOID ( *do_key_repeats_fn_ptr )();
#endif	/* NTVDM */

/*
 * 6805 code buffer:
 *
 * This is a cyclic buffer storing key events that have been accepted from
 * the host operating system, but not yet requested by the keyboard BIOS.
 *
 * It is equivalent to a 16 byte buffer present in the real keyboard hardware
 * on the PC-AT.
 *
 * We make the physical size of the buffer BUFF_6805_PMAX a power of 2
 * so that a mask BUFF_6805_PMASK can be used to wrap array indices quickly.
 *
 * Each character entered at the keyboard results in at least 3 bytes of
 * event data in the keyboard buffer. Thus the PC-AT's 16 byte buffer allows
 * at most 5 characters to be typed ahead. In practice this is never used
 * as the CPU is always active, allowing character data to be moved almost
 * immediately to the BIOS type ahead buffer.
 *
 * On SoftPC, however, the CPU can become inactive for significant periods;
 * at the same time, the keyboard hardware emulation may be forced to
 * process a large number of keyboard events from the host operating system.
 *
 * In order to give a constant amount of type ahead, regardless of where the
 * type ahead information is stored in SoftPC, we make the virtual size
 * of the hardware buffer BUFF_6805_VMAX 48 bytes long (16 characters X
 * 3 bytes of event data per character).
 */

/* 
   18.5.92 MG !!! TEMPORARY HACK !!! To fix windows bugs in Notepad and Word,
   set the buffer to 2k. Windows crashes when the keyboard buffer overflows,
   so we delay this for as long as sensible. It will still crash if you type
   too fast for too long.

   It works OK on a real PC, so the real reason it fails on SoftPC needs to
   be determined one day.

   20.5.92 MG - took out the hack - see below.
*/

#ifdef NTVDM	/* JonLe NT Mod */
#define	BUFF_6805_VMAX	496
#define	BUFF_6805_PMAX	512
#define	BUFF_6805_PMASK	(BUFF_6805_PMAX - 1)
#else
#define	BUFF_6805_VMAX	48
#define	BUFF_6805_PMAX	64
#define	BUFF_6805_PMASK	(BUFF_6805_PMAX - 1)
#endif	/* NTVDM */

#ifndef macintosh
static half_word buff_6805[BUFF_6805_PMAX];
#else
static half_word *buff_6805=NULL;
#endif /* macintosh */
static int buff_6805_in_ptr,buff_6805_out_ptr;

#ifdef NTVDM
static unsigned char key_marker_value = 0;
static unsigned char key_marker_buffer[BUFF_6805_PMAX];
int LastKeyDown= -1;
void Reset6805and8042(void);
#endif

/* 
   20.5.92 MG

   Real fix for my temporary hack in the last edition of this file.

   The problem with windows seems to be due to receipt of a huge
   number of overrun characters in a row, so now when we send an overrun
   character we set an 'overrun enable' flag, which is cleared when
   three bytes have been read from the buffer.

   The effect of this is to spread out the overruns, which seems to stop
   the illegal instructions occuring.

   Obviously this may have bad effects on real-mode DOS applications !!!
*/

LOCAL	BOOL	sent_overrun=FALSE;

#ifndef REAL_KBD
/* make arrays */
static int *make_sizes;
static half_word *make_arrays [134];

/* break arrays */
static int *break_sizes;
static half_word *break_arrays [134];

/* set 3 key states (eg. typematic, make/break, make only, typematic make/break) */

static half_word set_3_key_state [127];
#endif
static int key_down_count [127];


/* anomalous state handling variables */
half_word *anomalous_array;
int anomalous_size, anom_key;
int in_anomalous_state;

/* held events (while doing multiple code 6805 commands) */
#define	HELD_EVENT_MAX	16
int held_event_count;
int held_event_key[HELD_EVENT_MAX];
int held_event_type[HELD_EVENT_MAX];

#ifdef NTVDM 	/* JonLe NTVDM Mod:remove repeat related vars */
int scan_code_6805_size,key_set;
int input_port_val;
int waiting_for_next_code, waiting_for_next_8042_code, num_lock_on;
#else
int scan_code_6805_size,key_set,repeat_delay_target,repeat_target,repeat_delay_count,repeat_count;
int typematic_key, input_port_val;
int typematic_key_valid,waiting_for_next_code, waiting_for_next_8042_code, num_lock_on;
#endif	/* NTVDM */
int shift_on, l_shift_on, r_shift_on;
int ctrl_on, l_ctrl_on, r_ctrl_on;
int alt_on, l_alt_on, r_alt_on;
int waiting_for_upcode;
int next_code_sequence_number, next_8042_code_sequence_number, set_3_key_type_change_dest;
GLOBAL int free_6805_buff_size;	/* Must be global for NT VDM */
int translating, keyboard_disabled, int_enabled, output_full;
int pending_8042, keyboard_interface_disabled, scanning_discontinued;
half_word output_contents, pending_8042_value, kbd_status, op_port_remembered_bits, cmd_byte_8042;
half_word *scan_code_6805_array;
half_word scan_codes_temp_area[300];

#ifdef PM
int gate_a20_status;
#ifndef NTVDM
long reset_was_by_kbd = FALSE;
#endif
#endif

#ifndef NTVDM
int key_delay = 0;
half_word current_light_pattern;
#endif

#ifdef macintosh
/*
** The Mac cannot cope with loads of global data. So declare these
** as pointers and load the tables up from a Mac resource.
*/
half_word *keytypes;
int       *set_1_make_sizes, *set_2_make_sizes, *set_3_make_sizes;
int       *set_1_break_sizes, *set_2_break_sizes, *set_3_break_sizes;
half_word *trans_8042, *set_3_reverse_lookup, *set_3_default_key_state, *most_set_2_make_codes;
half_word *most_set_3_make_codes, *set_1_extra_codes, *set_2_extra_codes, *set_3_extra_codes;
half_word *set_1_extra_bk_codes, *set_2_extra_bk_codes, *set_3_extra_bk_codes, *buff_overrun_6805;
half_word *most_set_1_make_codes;

#else

#ifndef REAL_KBD
/* Data Tables */

static half_word keytypes[127] =
{ 0,0,0,0,0,0,0,0,0,0,  /* 0-9 */
  0,0,0,0,6,0,0,0,0,0,  /* 10-19 */
  0,0,0,0,0,0,0,0,0,0,  /* 20-29 */
  0,0,0,0,0,0,0,0,0,0,  /* 30-39 */
  0,0,0,0,0,0,0,0,0,0,  /* 40-49 */
  0,0,0,0,0,0,6,0,0,6,  /* 50-59 */
  0,0,1,6,1,6,6,6,6,6,  /* 60-69 */
  6,6,6,6,6,2,2,6,6,2,  /* 70-79 */
  2,2,6,2,2,2,2,6,6,2,  /* 80-89 */
  0,0,0,0,6,3,0,0,0,0,  /* 90-99 */
  0,0,0,0,0,0,0,6,1,6,  /* 100-109 */
  0,6,0,0,0,0,0,0,0,0,  /* 110-119 */
  0,0,0,0,4,0,5         /* 120-126 */
};

static int set_1_make_sizes [13]=
{ 1,2,2,2,4,6,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  2,			/* Num lock add size */
  2,			/* Left shift add size */
  2,			/* Right shift add size */
  2,			/* Case 4 shifted size */
  1,			/* Alt Case 4 size */
  4			/* Case 5 ctrled size */
};

static int set_2_make_sizes [13]=
{ 1,2,2,2,4,8,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  2,			/* Num lock add size */
  3,			/* Left shift add size */
  3,			/* Right shift add size */
  2,			/* Case 4 shifted size */
  1,			/* Alt Case 4 size */
  5			/* Case 5 ctrled size */
};

static int set_3_make_sizes [13]=
{ 1,1,1,1,1,1,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  0,			/* Num lock add size */
  0,			/* Left shift add size */
  0,			/* Right shift add size */
  1,			/* Case 4 shifted size */
  1,			/* Alt Case 4 size */
  1			/* Case 5 ctrled size */
};

static int set_1_break_sizes [13]=
{ 1,2,2,2,4,0,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  2,			/* Num lock add size */
  2,			/* Left shift add size */
  2,			/* Right shift add size */
  2,			/* Case 4 shifted size */
  1,			/* Alt Case 4 size */
  0			/* Case 5 ctrled size */
};

static int set_2_break_sizes [13]=
{ 2,3,3,3,6,0,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  3,			/* Num lock add size */
  2,			/* Left shift add size */
  2,			/* Right shift add size */
  3,			/* Case 4 shifted size */
  2,			/* Alt Case 4 size */
  0			/* Case 5 ctrled size */
};

static int set_3_break_sizes [13]=
{ 2,2,2,2,2,0,		/* categories 1 to 6 inclusive */
  0,			/* size for error case - non existant key */
  0,			/* Num lock add size */
  0,			/* Left shift add size */
  0,			/* Right shift add size */
  2,			/* Case 4 shifted size */
  2,			/* Alt Case 4 size */
  2			/* Case 5 ctrled size */
};

#endif

static half_word trans_8042 [256] =
{ 0xff,0x43,0x02,0x3f,0x3d,0x3b,0x3c,0x58,0x08,0x44,0x42,0x40,0x3e,0x0f,0x29,0x0f,		/* 00-0f */
  0x10,0x38,0x2a,0x13,0x1d,0x10,0x02,0x17,0x18,0x19,0x2c,0x1f,0x1e,0x11,0x03,0x1f,		/* 10-1f */
  0x20,0x2e,0x2d,0x20,0x12,0x05,0x04,0x27,0x28,0x39,0x2f,0x21,0x14,0x13,0x06,0x2f,		/* 20-2f */
  0x30,0x31,0x30,0x23,0x22,0x15,0x07,0x37,0x38,0x39,0x32,0x24,0x16,0x08,0x09,0x3f,		/* 30-3f */
  0x40,0x33,0x25,0x17,0x18,0x0b,0x0a,0x47,0x48,0x34,0x35,0x26,0x27,0x19,0x0c,0x4f,		/* 40-4f */
  0x50,0x51,0x28,0x53,0x1a,0x0d,0x56,0x57,0x3a,0x36,0x1c,0x1b,0x5c,0x2b,0x5e,0x5f,		/* 50-5f */
  0x60,0x56,0x62,0x63,0x64,0x65,0x0e,0x67,0x68,0x4f,0x6a,0x4b,0x47,0x6d,0x6e,0x6f,		/* 60-6f */
  0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54,		/* 70-7f */
  0x80,0x81,0x82,0x41,0x54,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,		/* 80-8f */
  0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,		/* 90-9f */
  0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,		/* a0-af */
  0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,		/* b0-bf */
  0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,		/* c0-cf */
  0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,		/* d0-df */
  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,		/* e0-ef */
  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff 		/* f0-ff */
};

#ifndef REAL_KBD
static half_word set_3_reverse_lookup [256]=
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x6e,0x00,0x00,0x00,0x00,0x10,0x01,0x71,		/* 00-0f */
  0x00,0x3a,0x2c,0x2d,0x1e,0x11,0x02,0x72,0x00,0x3c,0x2e,0x20,0x1f,0x12,0x03,0x73,		/* 10-1f */
  0x00,0x30,0x2f,0x21,0x13,0x05,0x04,0x74,0x00,0x3d,0x31,0x22,0x15,0x14,0x06,0x75,		/* 20-2f */
  0x00,0x33,0x32,0x24,0x23,0x16,0x07,0x76,0x00,0x3e,0x34,0x25,0x17,0x08,0x09,0x77,		/* 30-3f */
  0x00,0x35,0x26,0x18,0x19,0x0b,0x0a,0x78,0x00,0x36,0x37,0x27,0x28,0x1a,0x0c,0x79,		/* 40-4f */
  0x00,0x00,0x29,0x2a,0x1b,0x0d,0x7a,0x7c,0x40,0x39,0x2b,0x1c,0x1d,0x00,0x7b,0x7d,		/* 50-5f */
  0x54,0x4f,0x7e,0x53,0x4c,0x51,0x0f,0x4b,0x00,0x5d,0x59,0x5c,0x5b,0x56,0x50,0x55,		/* 60-6f */
  0x63,0x68,0x62,0x61,0x66,0x60,0x5a,0x5f,0x00,0x6c,0x67,0x00,0x6a,0x65,0x64,0x00,		/* 70-7f */
  0x00,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* 80-8f */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* 90-9f */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* a0-af */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* b0-bf */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* c0-cf */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* d0-df */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		/* e0-ef */
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 		/* f0-ff */
};

static half_word set_3_default_key_state [127]=
{ 0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x01,		/* 00-0f */
  0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,		/* 10-1f */
  0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,		/* 20-2f */
  0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x02,0x02,0x00,0x02,0x01,0x03,0x00,		/* 30-3f */
  0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x01,0x00,0x00,0x01,		/* 40-4f */
  0x03,0x03,0x00,0x01,0x01,0x03,0x03,0x00,0x00,0x01,0x03,0x03,0x03,0x03,0x00,0x03,		/* 50-5f */
  0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x00,0x03,0x00,0x03,0x00,		/* 60-6f */
  0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03           		/* 70-7d */
};

static half_word most_set_1_make_codes [127]=
{ 0x00,0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x00,0x0e,		/* 00-0f */
  0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x2b,0x3a,0x1e,		/* 10-1f */
  0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2b,0x1c,0x2a,0x56,0x2c,0x2d,		/* 20-2f */
  0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x00,0x36,0x1d,0x00,0x38,0x39,0x38,0x00,		/* 30-3f */
  0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x53,0x00,0x00,0x4b,		/* 40-4f */
  0x47,0x4f,0x00,0x48,0x50,0x49,0x51,0x00,0x00,0x4d,0x45,0x47,0x4b,0x4f,0x00,0x35,		/* 50-5f */
  0x48,0x4c,0x50,0x52,0x37,0x49,0x4d,0x51,0x53,0x4a,0x4e,0x00,0x1c,0x00,0x01,0x00,		/* 60-6f */
  0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x57,0x58,0x00,0x46,0x00			/* 70-7e */
};

static half_word most_set_2_make_codes [127]=
{ 0x00,0x0e,0x16,0x1e,0x26,0x25,0x2e,0x36,0x3d,0x3e,0x46,0x45,0x4e,0x55,0x00,0x66,		/* 00-0f */
  0x0d,0x15,0x1d,0x24,0x2d,0x2c,0x35,0x3c,0x43,0x44,0x4d,0x54,0x5b,0x5d,0x58,0x1c,		/* 10-1f */
  0x1b,0x23,0x2b,0x34,0x33,0x3b,0x42,0x4b,0x4c,0x52,0x5d,0x5a,0x12,0x61,0x1a,0x22,		/* 20-2f */
  0x21,0x2a,0x32,0x31,0x3a,0x41,0x49,0x4a,0x00,0x59,0x14,0x00,0x11,0x29,0x11,0x00,		/* 30-3f */
  0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x71,0x00,0x00,0x6b,		/* 40-4f */
  0x6c,0x69,0x00,0x75,0x72,0x7d,0x7a,0x00,0x00,0x74,0x77,0x6c,0x6b,0x69,0x00,0x4a,		/* 50-5f */
  0x75,0x73,0x72,0x70,0x7c,0x7d,0x74,0x7a,0x71,0x7b,0x79,0x00,0x5a,0x00,0x76,0x00,		/* 60-6f */
  0x05,0x06,0x04,0x0c,0x03,0x0b,0x83,0x0a,0x01,0x09,0x78,0x07,0x00,0x7e,0x00			/* 70-7e */
};

static half_word most_set_3_make_codes [127]=
{ 0x00,0x0e,0x16,0x1e,0x26,0x25,0x2e,0x36,0x3d,0x3e,0x46,0x45,0x4e,0x55,0x00,0x66,		/* 00-0f */
  0x0d,0x15,0x1d,0x24,0x2d,0x2c,0x35,0x3c,0x43,0x44,0x4d,0x54,0x5b,0x5c,0x14,0x1c,		/* 10-1f */
  0x1b,0x23,0x2b,0x34,0x33,0x3b,0x42,0x4b,0x4c,0x52,0x53,0x5a,0x12,0x13,0x1a,0x22,		/* 20-2f */
  0x21,0x2a,0x32,0x31,0x3a,0x41,0x49,0x4a,0x00,0x59,0x11,0x00,0x19,0x29,0x39,0x00,		/* 30-3f */
  0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x64,0x00,0x00,0x61,		/* 40-4f */
  0x6e,0x65,0x00,0x63,0x60,0x6f,0x6d,0x00,0x00,0x6a,0x76,0x6c,0x6b,0x69,0x00,0x77,		/* 50-5f */
  0x75,0x73,0x72,0x70,0x7e,0x7d,0x74,0x7a,0x71,0x84,0x7c,0x00,0x79,0x00,0x08,0x00,		/* 60-6f */
  0x07,0x0f,0x17,0x1f,0x27,0x2f,0x37,0x3f,0x47,0x4f,0x56,0x5e,0x57,0x5f,0x62			/* 70-7e */
};

static half_word set_1_extra_codes []=
{ 0xe0,0x2a,0xe0,0x37,				/* Case 4 norm */
  0xe1,0x1d,0x45,0xe1,0x9d,0xc5,		/* Case 5 norm */
  						/* Error case -non existant (empty) */
  0xe0,0x2a,					/* Num lock add sequence */
  0xe0,0xaa,					/* Left shift add sequence */
  0xe0,0xb6,					/* Right shift add sequence */
  0xe0,0x37,					/* case 4 shifted */
  0x54,						/* Alt case 4 */
  0xe0,0x46,0xe0,0xc6				/* Case 5 ctrled */
};

static half_word set_2_extra_codes []=
{ 0xe0,0x12,0xe0,0x7c,				/* Case 4 norm */
  0xe1,0x14,0x77,0xe1,0xf0,0x14,0xf0,0x77,	/* Case 5 norm */
  						/* Error case -non existant (empty) */
  0xe0,0x12,					/* Num lock add sequence */
  0xe0,0xf0,0x12,				/* Left shift add sequence */
  0xe0,0xf0,0x59,				/* Right shift add sequence */
  0xe0,0x7c,					/* case 4 shifted */
  0x84,						/* Alt case 4 */
  0xe0,0x7e,0xe0,0xf0,0x7e			/* Case 5 ctrled */
};


static half_word set_3_extra_codes []=
{ 0x57,						/* Case 4 norm */
  0x62,						/* Case 5 norm */
  						/* Error case -non existant (empty) */
    						/* Num lock add sequence (empty) */
  						/* Left shift add sequence (empty) */
  						/* Right shift add sequence (empty) */
  0x57,						/* case 4 shifted */
  0x57,						/* Alt case 4 */
  0x62						/* Case 5 ctrled */
};


static half_word set_1_extra_bk_codes []=
{ 0xe0,0xb7,0xe0,0xaa,				/* Case 4 norm */
  						/* Case 5 norm (empty) */
  						/* Error case -non existant (empty) */
  0xe0,0xaa,					/* Num lock add sequence */
  0xe0,0x2a,					/* Left shift add sequence */
  0xe0,0x36,					/* Right shift add sequence */
  0xe0,0xb7,					/* case 4 shifted */
  0xd4,						/* Alt case 4 */
  						/* Case 5 ctrled (empty) */
};

static half_word set_2_extra_bk_codes []=
{ 0xe0,0xf0,0x7c,0xe0,0xf0,0x12,		/* Case 4 norm */
  						/* Case 5 norm (empty) */
  						/* Error case -non existant (empty) */
  0xe0,0xf0,0x12,				/* Num lock add sequence */
  0xe0,0x12,					/* Left shift add sequence */
  0xe0,0x59,					/* Right shift add sequence */
  0xe0,0xf0,0x7c,				/* case 4 shifted */
  0xf0,0x84					/* Alt case 4 */
  						/* Case 5 ctrled (empty) */
};


static half_word set_3_extra_bk_codes []=
{ 0xf0,0x57,					/* Case 4 norm */
  						/* Case 5 norm (empty) */
  						/* Error case -non existant (empty) */
    						/* Num lock add sequence (empty) */
  						/* Left shift add sequence (empty) */
  						/* Right shift add sequence (empty) */
  0xf0,0x57,					/* case 4 shifted */
  0xf0,0x57,					/* Alt case 4 */
  0xf0,0x62					/* Case 5 ctrled */
};
#endif

static half_word buff_overrun_6805 [4]=
{ 
  0,0xff,0,0
};

#endif /* macintosh */

LOCAL VOID calc_buff_6805_left IPT0();
LOCAL VOID do_host_key_down IPT1( int,key );
LOCAL VOID do_host_key_up IPT1( int,key );
LOCAL VOID codes_to_translate IPT0();
GLOBAL VOID continue_output IPT0();
LOCAL VOID cmd_to_8042 IPT1( half_word,cmd_code );
LOCAL VOID cmd_to_6805 IPT1( half_word,cmd_code );
#ifndef HUNTER
LOCAL INT buffer_status_8042 IPT0();
#endif

/*
 * 6805 code buffer access procedures
 */

/*(
=============================== keyba_running ==================================
PURPOSE:
	This access function is used to by other modules to check whether
keyba.c is currently passing on keyboard events, or whether it is buffering
them.  This allows calling functions to avoid filling up keyba's buffers.

INPUT:
None.

OUTPUT:
The return value is true if keystrokes are being passed on.

ALGORITHM:
If the scanning_discontinued flag is set, or if the 6905 buffer is not
empty, FALSE is returned.
================================================================================
)*/
GLOBAL BOOL
keyba_running IFN0()
{
	if (scanning_discontinued || (buff_6805_in_ptr != buff_6805_out_ptr))
		return(FALSE);
	else
		return(TRUE);
}

#define QUEUED_OUTPUT    0
#define IMMEDIATE_OUTPUT 1

LOCAL VOID add_to_6805_buff IFN2(half_word,code,int, immediate)
/* immediate --->   = 0 queue on buffer end,
		    = 1 queue on buffer start */
	{
   /* iff room in buffer */
   if (((buff_6805_out_ptr -1)& BUFF_6805_PMASK) != buff_6805_in_ptr)
      {
      if ( immediate )
	 {
	 /* queue at start */
	 buff_6805_out_ptr = (buff_6805_out_ptr - 1) & BUFF_6805_PMASK;
	 buff_6805[buff_6805_out_ptr]=code;
	 }
      else
	 {
	 /* queue at end */
	buff_6805[buff_6805_in_ptr]=code;
	buff_6805_in_ptr = (buff_6805_in_ptr + 1) & BUFF_6805_PMASK;
	}
      }
   calc_buff_6805_left();

#ifdef NTVDM	/* JonLe NTVDM Mod */
   /*
    *  Look ahead to see if we have a reasonable amount of space left
    *  if not then we must slow down the event thread by setting
    *  hKbdNotFullEvent to the not-signalled state
    */
   if (KbdHdwFull < BUFF_6805_VMAX/2 &&
       BUFF_6805_VMAX - free_6805_buff_size >= BUFF_6805_VMAX/2)
   {
       HostResetKbdNotFullEvent();
       bKbdNotFullReset = TRUE;
   }
   KbdHdwFull = BUFF_6805_VMAX - free_6805_buff_size;
#endif	/* NTVDM */

   } /* end of add_to_6805_buff */

static half_word remove_from_6805_buff IFN0()
{
half_word ch;

ch=buff_6805[buff_6805_out_ptr];

#ifdef NTVDM
	key_marker_buffer[buff_6805_out_ptr]=0;
#endif

if (buff_6805_out_ptr != buff_6805_in_ptr)
	{
	buff_6805_out_ptr = (buff_6805_out_ptr +1) & BUFF_6805_PMASK;
	}
calc_buff_6805_left();

#ifdef NTVDM
   /*
    *  If hKbdNotFullEvent is not in the signalled-state
    *  then set it to the signalled state
    */
   if (bKbdNotFullReset && free_6805_buff_size == BUFF_6805_VMAX)
   {
       bKbdNotFullReset = FALSE;
       HostSetKbdNotFullEvent();
   }
   KbdHdwFull = BUFF_6805_VMAX - free_6805_buff_size;
#endif	/* NTVDM */

return (ch);
} /* end of remove_from_6805_buff */


LOCAL VOID clear_buff_6805 IFN0()
{
	/* 18/5/92 MG On a macintosh, allocate buffer space so that we're
	   not grabbing it from the global allocation. */

#ifdef macintosh
	if (buff_6805==NULL) {
		check_malloc(buff_6805,BUFF_6805_PMAX,half_word);
	}
#endif /* macintosh */

	buff_6805_in_ptr=buff_6805_out_ptr;
	free_6805_buff_size=BUFF_6805_VMAX;

#ifdef NTVDM
   /*
    *  If hKbdNotFullEvent is not in the signalled-state
    *  and there is enuf space in the 6805 then signal the
    *  event thread to continue processing.
    */
    if (bKbdNotFullReset)
    {
        bKbdNotFullReset = FALSE;
        HostSetKbdNotFullEvent();
    }
    KbdHdwFull = BUFF_6805_VMAX - free_6805_buff_size;

    /* Clear key marker buffer */
    {
	register int loop = sizeof(key_marker_buffer) / sizeof(unsigned char);
	while(--loop >= 0) key_marker_buffer[loop] = 0;
    }
#endif	/* NTVDM */
}

#ifdef NTVDM

#define ONECHARCODEMASK (0x80)

LOCAL VOID mark_key_codes_6805_buff IFN1(int, start)
{
   static int start_offset;

   /* Room in buffer */
   if(((buff_6805_out_ptr -1)& BUFF_6805_PMASK) != buff_6805_in_ptr)
   {

	/* Bump key start/end marker is start of seq */
	if(start)
	{
	    start_offset = buff_6805_in_ptr;
	    if(++key_marker_value > 127) key_marker_value = 1;
	}
	else
	{
	    //End of seq, mark first & last byte

	    if(start_offset != buff_6805_in_ptr)
	    {

		key_marker_buffer[start_offset] = key_marker_value;

		if(((buff_6805_in_ptr -1)& BUFF_6805_PMASK) == start_offset)
		{
		key_marker_buffer[(buff_6805_in_ptr -1)& BUFF_6805_PMASK] =
				  key_marker_value | ONECHARCODEMASK;
		}
		else
		{
		//mult byte seq

		key_marker_buffer[(buff_6805_in_ptr -1)& BUFF_6805_PMASK] =
				  key_marker_value;
		}
	    }
	}
   }
}

//This function returns the number of keys in the 6805 buffers and also
//clears down these buffers

GLOBAL int keys_in_6805_buff(int *part_key_transferred)
{
    int keys_in_buffer = held_event_count;  //key to yet processed by adapter
    int tmp_6805_out_ptr;
    char last_marker = 0;

    *part_key_transferred = FALSE;

    for(tmp_6805_out_ptr = buff_6805_out_ptr;
	tmp_6805_out_ptr != buff_6805_in_ptr;
	tmp_6805_out_ptr = (tmp_6805_out_ptr +1) & BUFF_6805_PMASK)
    {
	if(key_marker_buffer[tmp_6805_out_ptr] != 0)
	{
	    if(last_marker == 0)
	    {
		//start of key seq found
		if(key_marker_buffer[tmp_6805_out_ptr] & ONECHARCODEMASK)
		    keys_in_buffer++; //one byte seq		else
		    last_marker = key_marker_buffer[tmp_6805_out_ptr];
	    }
	    else
	    {
		if(key_marker_buffer[tmp_6805_out_ptr] == last_marker)
		{
		    keys_in_buffer++;//End of key seq found, bump key count
		    last_marker = 0; //no longer in middle of key seq
		}
		else
		{
		    //Scan terminate early, part key seq found
		    *part_key_transferred = TRUE;
		    last_marker = key_marker_buffer[tmp_6805_out_ptr];
		}
	    }
	}
    }

    // Terminated scan in middle of key seq ???
    if(last_marker) *part_key_transferred = TRUE;


    // Is there currently a key in the one char 8042 buffer
    if(output_full)
    {
	keys_in_buffer++;
    }

    Reset6805and8042();

    return(keys_in_buffer);
}

void Reset6805and8042()
{
    int key;

    /* Reset 6805 */

    buff_6805_out_ptr=0;
    clear_buff_6805();

    for(key = 0; key < 127; key++)
    {
	set_3_key_state [key] = set_3_default_key_state[key];
	key_down_count[key]=0;
    }

    waiting_for_next_code=waiting_for_next_8042_code=FALSE;

    shift_on = l_shift_on = r_shift_on = FALSE;
    ctrl_on = l_ctrl_on = r_ctrl_on = FALSE;
    alt_on = l_alt_on = r_alt_on = FALSE;
    waiting_for_upcode = FALSE;

    /* Reset 8042 */

    kbd_status = 0x14;
    cmd_byte_8042 = 0x45;
    keyboard_disabled = keyboard_interface_disabled = FALSE;
    op_port_remembered_bits = 0xc;

    pending_8042 = output_full = in_anomalous_state = FALSE;
    int_enabled = translating = TRUE;
    scanning_discontinued = FALSE;
    held_event_count = 0;
    num_lock_on = TRUE;
}

#endif /* NTVDM */

LOCAL VOID calc_buff_6805_left IFN0()
{
free_6805_buff_size = BUFF_6805_VMAX-((buff_6805_in_ptr - buff_6805_out_ptr) & BUFF_6805_PMASK);
if (free_6805_buff_size<0) 
	{
	free_6805_buff_size=0;
	sure_note_trace0(AT_KBD_VERBOSE,"Keyboard buffer full");
	}
} /* end of calc_buff_6805_left */

LOCAL VOID add_codes_to_6805_buff IFN2(int,codes_size,half_word *,codes_buff)
{
int code_index;

if (free_6805_buff_size < codes_size)
	{

/* 20.5.92 MG Don't send the overrun if we only just sent one */

	if (!sent_overrun)
		add_to_6805_buff(buff_overrun_6805[key_set], QUEUED_OUTPUT);
	sent_overrun=TRUE;
	sure_note_trace0(AT_KBD_VERBOSE,"Keyboard buffer overrun");
	}
else
	{

/* If some characters have been read out, clear the sent_overrun flag */

	if (free_6805_buff_size>(codes_size+3))
		sent_overrun=FALSE;
	for (code_index=0;code_index<codes_size;code_index++) {
		add_to_6805_buff(codes_buff[code_index], QUEUED_OUTPUT);
		}
	}
} /* end of add_codes_to_6805_buff */


#ifndef REAL_KBD
/* initialisation code */

LOCAL VOID init_key_arrays IFN0()
{
int key;
half_word *next_free, *extra_ptr, *extra_bk_ptr;

sure_note_trace1(AT_KBD_VERBOSE,"Keyboard key set initialisation: key set %d",key_set);
next_free = scan_codes_temp_area;
switch (key_set)
	{
	case 1:
		make_sizes=set_1_make_sizes;
		break_sizes=set_1_break_sizes;
		for (key=0;key<127;key++)
			{
			switch (keytypes[key])
				{
				case 0:
					make_arrays[key]= &(most_set_1_make_codes[key]);
					break_arrays[key]=next_free;
					*next_free++=(most_set_1_make_codes[key])^0x80;
					break;
				case 1:
				case 2:
				case 3:
					make_arrays[key]=next_free;
					*next_free++ = 0xe0;
					*next_free++ = most_set_1_make_codes[key];
					break_arrays[key]=next_free;
					*next_free++ = 0xe0;
					*next_free++ = (most_set_1_make_codes[key]) ^ 0x80;
					break;
				}
			}
		extra_ptr=set_1_extra_codes;
		extra_bk_ptr=set_1_extra_bk_codes;
		break;
	case 2:
		make_sizes=set_2_make_sizes;
		break_sizes=set_2_break_sizes;
		for (key=0;key<127;key++)
			{
			switch (keytypes[key])
				{
				case 0:
					make_arrays[key]= &(most_set_2_make_codes[key]);
					break_arrays[key]=next_free;
					*next_free++ = 0xf0;
					*next_free++ = most_set_2_make_codes[key];
					break;
				case 1:
				case 2:
				case 3:
					make_arrays[key]=next_free;
					*next_free++ = 0xe0;
					*next_free++ = most_set_2_make_codes[key];
					break_arrays[key]=next_free;
					*next_free++ = 0xe0;
					*next_free++ = 0xf0;
					*next_free++ = most_set_2_make_codes[key];
					break;
				}
			}
		extra_ptr=set_2_extra_codes;
		extra_bk_ptr=set_2_extra_bk_codes;
		break;
	case 3:
		make_sizes=set_3_make_sizes;
		break_sizes=set_3_break_sizes;
		for (key=0;key<127;key++)
			{
			if (keytypes[key] != 6)
				{
				make_arrays[key]= &(most_set_3_make_codes[key]);
				break_arrays[key]=next_free;
				*next_free++ = 0xf0;
				*next_free++ = most_set_3_make_codes[key];
				}
			}
		extra_ptr=set_3_extra_codes;
		extra_bk_ptr=set_3_extra_bk_codes;
		break;
	} /* end of switch */

	make_arrays[124]=extra_ptr;
	extra_ptr+=make_sizes[4];
	make_arrays[126]=extra_ptr;
	extra_ptr+=make_sizes[5];
	extra_ptr+=make_sizes[6];
	make_arrays[NUM_LOCK_ADD_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[7];
	make_arrays[L_SHIFT_ADD_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[8];
	make_arrays[R_SHIFT_ADD_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[9];
	make_arrays[CASE_4_SHIFTED_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[10];
	make_arrays[ALT_CASE_4_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[11];
	make_arrays[CASE_5_CTRLED_ARRAY]=extra_ptr;
	extra_ptr+=make_sizes[12];

	break_arrays[124]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[4];
	break_arrays[126]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[5];
	extra_bk_ptr+=break_sizes[6];
	break_arrays[NUM_LOCK_ADD_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[7];
	break_arrays[L_SHIFT_ADD_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[8];
	break_arrays[R_SHIFT_ADD_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[9];
	break_arrays[CASE_4_SHIFTED_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[10];
	break_arrays[ALT_CASE_4_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[11];
	break_arrays[CASE_5_CTRLED_ARRAY]=extra_bk_ptr;
	extra_bk_ptr+=break_sizes[12];
} /* end of init_key_arrays () */


/* Key pressed on host keyboard */

GLOBAL VOID host_key_down IFN1(int,key)
{

    if (scanning_discontinued)  {
       held_event_type[held_event_count]=KEY_DOWN_EVENT;
       held_event_key[held_event_count++]=key;

       /* check for held event buffer overflow (SHOULD never happen) */
       if (held_event_count >= HELD_EVENT_MAX)  {
           held_event_count = HELD_EVENT_MAX-1;
           always_trace0("host_key_down held event buffer overflow");
           }
       }
    else if (!keyboard_disabled) {
#ifdef NTVDM
       //
       // Ignore contiguous repeat keys if keys are still in the 6805
       // this keeps the apps responsive to the corresponding up key
       // when it comes.
       //
       if (LastKeyDown != key || (!KbdHdwFull && !output_full)) {
           LastKeyDown = key;
           key_down_count[key]++;
           do_host_key_down(key);
           }
#else
       key_down_count[key]++;
       do_host_key_down(key);
#endif
       }
}

GLOBAL VOID host_key_up IFN1(int,key)
{

   if (scanning_discontinued)  {
       held_event_type[held_event_count]=KEY_UP_EVENT;
       held_event_key[held_event_count++]=key;

       /* check for held event buffer overflow (SHOULD never happen) */
       if (held_event_count >= HELD_EVENT_MAX) {
           held_event_count = HELD_EVENT_MAX-1;
           always_trace0("host_key_up held event buffer overflow");
           }
       }
   else if (!keyboard_disabled && key_down_count[key]) {
       key_down_count[key] =  0;
#ifdef NTVDM
       LastKeyDown = -1;
#endif
       do_host_key_up(key);
       }
}

#ifdef NTVDM
GLOBAL VOID RaiseAllDownKeys(VOID)
{
   int i;

   i = sizeof(key_down_count)/sizeof(int);
   while (i--) {
       if (key_down_count[i]) {
           host_key_up(i);
           }
       }
}

GLOBAL int IsKeyDown(int Key)
{
   return  key_down_count[Key];
}


#endif

LOCAL VOID do_host_key_down IFN1(int,key)
{
int overrun,keytype;

sure_note_trace1(AT_KBD_VERBOSE,"key down:%d",key);

#ifdef NTVDM
       mark_key_codes_6805_buff(TRUE);
          {
#else
       if (key_down_count[key]==1)
          {                          /* first press */
           repeat_delay_count=0;
           repeat_count=0;
           typematic_key_valid=FALSE;

#endif
           keytype=keytypes[key];
           overrun=FALSE;
           if (in_anomalous_state) {
               if (anomalous_size > free_6805_buff_size)
                       { overrun=TRUE; }
               else
                       {
                       scan_code_6805_size = anomalous_size;
                       scan_code_6805_array = anomalous_array;
                       add_codes_to_6805_buff(anomalous_size,anomalous_array);
                       in_anomalous_state=FALSE;
                       }
               }

           switch (keytype)  {
               case 0:
               case 1:
               case 6:
                   scan_code_6805_size=make_sizes[keytype];
                   scan_code_6805_array=make_arrays[key];
                   break;
               case 2:
                   if (num_lock_on && !shift_on)
                           {
                           scan_code_6805_size=make_sizes[NUM_LOCK_ADD];
                           scan_code_6805_array=make_arrays[NUM_LOCK_ADD_ARRAY];
                           if (scan_code_6805_size+make_sizes[keytype] >free_6805_buff_size)
                                   { overrun=TRUE; }
                           else
                               {
                               in_anomalous_state=TRUE;
                               anom_key=key;
                               anomalous_array=break_arrays[NUM_LOCK_ADD_ARRAY];
                               anomalous_size=break_sizes[NUM_LOCK_ADD];
                               add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                               }
                           }
                   if (!num_lock_on && shift_on)
                           {
                           if (l_shift_on)
                                   {
                                   scan_code_6805_size=make_sizes[L_SHIFT_ADD];
                                   scan_code_6805_array=make_arrays[L_SHIFT_ADD_ARRAY];
                               in_anomalous_state=TRUE;
                               anom_key=key;
                               anomalous_array=break_arrays[L_SHIFT_ADD_ARRAY];
                               anomalous_size=break_sizes[L_SHIFT_ADD];
                                   }
                           else
                                   {
                                   scan_code_6805_size=make_sizes[R_SHIFT_ADD];
                                   scan_code_6805_array=make_arrays[R_SHIFT_ADD_ARRAY];
                               in_anomalous_state=TRUE;
                               anom_key=key;
                               anomalous_array=break_arrays[R_SHIFT_ADD_ARRAY];
                               anomalous_size=break_sizes[R_SHIFT_ADD];
                                   }
                           if (scan_code_6805_size+make_sizes[keytype] >free_6805_buff_size)
                                   {
                                   overrun=TRUE;
                                   in_anomalous_state=FALSE;
                                   }
                           else
                                   {
                                   add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                                   }
                           }
                   scan_code_6805_size=make_sizes[keytype];
                   scan_code_6805_array=make_arrays[key];
                   break;
               case 3:
                   if (shift_on)
                           {
                           if (l_shift_on)
                                   {
                                   scan_code_6805_size=make_sizes[L_SHIFT_ADD];
                                   scan_code_6805_array=make_arrays[L_SHIFT_ADD_ARRAY];
                               in_anomalous_state=TRUE;
                               anom_key=key;
                               anomalous_array=break_arrays[L_SHIFT_ADD_ARRAY];
                               anomalous_size=break_sizes[L_SHIFT_ADD];
                                   }
                           else
                                   {
                                   scan_code_6805_size=make_sizes[R_SHIFT_ADD];
                                   scan_code_6805_array=make_arrays[R_SHIFT_ADD_ARRAY];
                               in_anomalous_state=TRUE;
                               anom_key=key;
                               anomalous_array=break_arrays[R_SHIFT_ADD_ARRAY];
                               anomalous_size=break_sizes[R_SHIFT_ADD];
                                   }
                           if (scan_code_6805_size+make_sizes[keytype] >free_6805_buff_size)
                                   {
                                   overrun=TRUE;
                                   in_anomalous_state=FALSE;
                                   }
                           else
                                   {
                                   add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                                   }
                           }
                   scan_code_6805_size=make_sizes[keytype];
                   scan_code_6805_array=make_arrays[key];
                   break;
               case 4:
                   if (shift_on || ctrl_on || alt_on)
                           {
                           if (shift_on || ctrl_on)
                                   {
                                   scan_code_6805_size=make_sizes[CASE_4_SHIFTED];
                                   scan_code_6805_array=make_arrays[CASE_4_SHIFTED_ARRAY];
                                   }
                           else
                                   {
                                   scan_code_6805_size=make_sizes[ALT_CASE_4];
                                   scan_code_6805_array=make_arrays[ALT_CASE_4_ARRAY];
                                   }
                           }
                   else
                           {
                               in_anomalous_state=TRUE;
                               anomalous_array=break_arrays[L_SHIFT_ADD_ARRAY];
                               anomalous_size=break_sizes[L_SHIFT_ADD];
                               anom_key=key;
                           scan_code_6805_size=make_sizes[keytype];
                           scan_code_6805_array=make_arrays[key];
                           }
                   break;
               case 5:
                   if (ctrl_on)
                           {
                           scan_code_6805_size=make_sizes[CASE_5_CTRLED];
                           scan_code_6805_array=make_arrays[CASE_5_CTRLED_ARRAY];
                           }
                   else
                           {
                           scan_code_6805_size=make_sizes[keytype];
                           scan_code_6805_array=make_arrays[key];
                           }
                   break;
               } /* end of switch */

           if (overrun)  {
               if (!sent_overrun)
                       add_to_6805_buff(buff_overrun_6805[key_set],
                               QUEUED_OUTPUT);
               sent_overrun=TRUE;

               sure_note_trace0(AT_KBD_VERBOSE,"Keyboard buffer overrun");
               }
           else  {
               add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
               }
           switch (key)  {
               case 44:
                       l_shift_on =TRUE;
                       shift_on = TRUE;
                       break;
               case 57:
                       r_shift_on = TRUE;
                       shift_on = TRUE;
                       break;
               case 58:
                       l_ctrl_on =TRUE;
                       ctrl_on = TRUE;
                       break;
               case 64:
                       r_ctrl_on = TRUE;
                       ctrl_on = TRUE;
                       break;
               case 60:
                       l_alt_on =TRUE;
                       alt_on = TRUE;
                       break;
               case 62:
                       r_alt_on =TRUE;
                       alt_on = TRUE;
                       break;
               case 90:
                       num_lock_on = !num_lock_on;
                       break;
               }

#ifndef NTVDM

           if (key!=126) {
               if ((key_set != 3) || (set_3_key_state[key] == 1) || (set_3_key_state[key] == 4))
                       {
                       typematic_key = key;
                       typematic_key_valid = TRUE;
                       }
               }
#else
           mark_key_codes_6805_buff(FALSE);
#endif

           if (free_6805_buff_size < BUFF_6805_VMAX) {
               codes_to_translate();
               }

           } /* end of if first press */


} /* end of do_host_key_down */


/* Key released on host keyboard */
LOCAL VOID do_host_key_up IFN1(int,key)
{
half_word *temp_arr_array;
int temp_arr_size,keytype,overrun;

sure_note_trace1(AT_KBD_VERBOSE,"key up:%d",key);

#ifdef DEMO_COPY
	host_check_demo_expire ();
#endif

#ifndef NTVDM
        if ((key==typematic_key) && typematic_key_valid) {
             typematic_key_valid=FALSE;
             }
#endif

        keytype=keytypes[key];
        overrun=FALSE;
        if (!(key_set ==3) || (set_3_key_state[key]==2) || (set_3_key_state[key]==4))
          {
#ifdef NTVDM
            mark_key_codes_6805_buff(TRUE);
#endif
            switch (keytype) {
                case 0:
                case 1:
                case 6:
                        scan_code_6805_size=break_sizes[keytype];
                        scan_code_6805_array=break_arrays[key];
                        break;
                case 2:
                        temp_arr_size=0;
                        if (in_anomalous_state && (anom_key == key))
                                {
                                in_anomalous_state=FALSE;
                                if (num_lock_on && !shift_on)
                                        {
                                        temp_arr_size=break_sizes[NUM_LOCK_ADD];
                                        temp_arr_array=break_arrays[NUM_LOCK_ADD_ARRAY];
                                        }
                                if (!num_lock_on && shift_on)
                                        {
                                        if (l_shift_on)
                                                {
                                                temp_arr_size=break_sizes[L_SHIFT_ADD];
                                                temp_arr_array=break_arrays[L_SHIFT_ADD_ARRAY];
                                                }
                                        else
                                                {
                                                temp_arr_size=break_sizes[R_SHIFT_ADD];
                                                temp_arr_array=break_arrays[R_SHIFT_ADD_ARRAY];
                                                }
                                        }
                                }
                        scan_code_6805_size=break_sizes[keytype];
                        scan_code_6805_array=break_arrays[key];
                        if (scan_code_6805_size+temp_arr_size > free_6805_buff_size)
                                { overrun=TRUE; }
                        else
                                {
                                add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                                }
                        scan_code_6805_size=temp_arr_size;
                        scan_code_6805_array=temp_arr_array;
                        break;
                case 3:
                        temp_arr_size=0;
                        if (in_anomalous_state && (anom_key == key))
                                {
                                in_anomalous_state = FALSE;
                                if (shift_on)
                                        {
                                        if (l_shift_on)
                                                {
                                                temp_arr_size=break_sizes[L_SHIFT_ADD];
                                                temp_arr_array=break_arrays[L_SHIFT_ADD_ARRAY];
                                                }
                                        else
                                                {
                                                temp_arr_size=break_sizes[R_SHIFT_ADD];
                                                temp_arr_array=break_arrays[R_SHIFT_ADD_ARRAY];
                                                }
                                        }
                                }
                        scan_code_6805_size=break_sizes[keytype];
                        scan_code_6805_array=break_arrays[key];
                        if (scan_code_6805_size+temp_arr_size > free_6805_buff_size)
                                { overrun=TRUE; }
                        else
                                {
                                add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                                }
                        scan_code_6805_size=temp_arr_size;
                        scan_code_6805_array=temp_arr_array;
                        break;
                case 4:
                        if (shift_on || ctrl_on || alt_on)
                                {
                                if (shift_on || ctrl_on)
                                        {
                                        scan_code_6805_size=break_sizes[CASE_4_SHIFTED];
                                        scan_code_6805_array=break_arrays[CASE_4_SHIFTED_ARRAY];
                                        }
                                else
                                        {
                                        scan_code_6805_size=break_sizes[ALT_CASE_4];
                                        scan_code_6805_array=break_arrays[ALT_CASE_4_ARRAY];
                                        }
                                }
                        else
                                {
                                if (in_anomalous_state && (anom_key==key))
                                        {
                                        in_anomalous_state=FALSE;
                                        scan_code_6805_size=break_sizes[keytype];
                                        scan_code_6805_array=break_arrays[key];
                                        }
                                else
                                        {
                                        scan_code_6805_size=break_sizes[CASE_4_SHIFTED];
                                        scan_code_6805_array=break_arrays[CASE_4_SHIFTED_ARRAY];
                                        }
                                }
                        break;
                case 5:
                        scan_code_6805_size=0;
                        break;
                } /* end of switch */

            if (overrun) {
                if (!sent_overrun)
                        add_to_6805_buff(buff_overrun_6805[key_set], QUEUED_OUTPUT);
                sent_overrun=TRUE;

                sure_note_trace0(AT_KBD_VERBOSE,"Keyboard buffer overrun");
                }
            else  {
                add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
                }
#ifdef NTVDM
            mark_key_codes_6805_buff(FALSE);
#endif
            } /* end of if not set 3 etc. */

        switch (key) {
            case 44:
                    l_shift_on =FALSE;
                    if (!r_shift_on) { shift_on = FALSE; }
                    break;
            case 57:
                    r_shift_on = FALSE;
                    if (!l_shift_on) { shift_on = FALSE; }
                    break;
            case 58:
                    l_ctrl_on =FALSE;
                    if (!r_ctrl_on) { ctrl_on = FALSE; }
                    break;
            case 64:
                    r_ctrl_on = FALSE;
                    if (!l_ctrl_on) { ctrl_on = FALSE; }
                    break;
            case 60:
                    l_alt_on =FALSE;
                    if (!r_alt_on) { alt_on = FALSE; }
                    break;
            case 62:
                    r_alt_on =FALSE;
                    if (!l_alt_on) { alt_on = FALSE; }
                    break;
            } /* end of switch */

        if (free_6805_buff_size < BUFF_6805_VMAX) {
            codes_to_translate();
            }

} /* end of do_host_key_up */
#endif /* REAL_KBD */

#ifdef NTVDM
        //
        //  force filling of Kbd data port just like the real kbd
        //  since we no longer clear output_full in the Kbd_inb routine
        //
LOCAL VOID AddTo6805BuffImm IFN1(half_word,code)
{
  add_to_6805_buff(code,IMMEDIATE_OUTPUT);
  output_full = FALSE;
  KbdData = -1;
}
#else
#define  AddTo6805BuffImm(code) add_to_6805_buff(code, IMMEDIATE_OUTPUT);
#endif

LOCAL VOID cmd_to_6805 IFN1(half_word,cmd_code)
{
int i,key_to_change;
half_word change_to;
unsigned int cmd_code_temp; /* Mac MPW3 compiler prefers unsigned ints in switches */

sure_note_trace1(AT_KBD_VERBOSE,"6805 received cmd:0x%x",cmd_code);

#ifndef REAL_KBD

if (waiting_for_next_code)
	{
	switch (next_code_sequence_number)
		{
		case SCAN_CODE_CHANGE_SEQUENCE:
			if (cmd_code>3 || cmd_code <0)
                                { AddTo6805BuffImm(RESEND_CODE); }
			else
				{
				 if (cmd_code == 0)
					{
					/* order of reception of scan codes is reverse their order of insertion
					 * if 'IMMEDIATE_OUTPUT' method of insertion is used
					 */
                                         AddTo6805BuffImm((half_word)key_set);
                                         AddTo6805BuffImm(ACK_CODE);
					}
				 else
					{
                                         AddTo6805BuffImm(ACK_CODE);
					 key_set=cmd_code;
					 init_key_arrays();
					}
				}
			break;
		case SET_3_KEY_TYPE_SET_SEQUENCE:
			sure_note_trace2(AT_KBD_VERBOSE,"Keyboard key type change: key 0x%x, new type %d",cmd_code,set_3_key_type_change_dest);
                        AddTo6805BuffImm(ACK_CODE);
			key_to_change=set_3_reverse_lookup[cmd_code];
			set_3_key_state[key_to_change]=set_3_key_type_change_dest;
			break;
		case SET_STATUS_INDICATORS_SEQUENCE:
			if ((cmd_code & 0xf8) == 0)
			{
			sure_note_trace1(AT_KBD_VERBOSE,"Changing kbd lights to :%x",cmd_code);
                        AddTo6805BuffImm(ACK_CODE);
#ifdef NTVDM
                        host_kb_light_on (cmd_code & 0x07);
#else
                        cmd_code &= 0x7;
                        host_kb_light_on (cmd_code);
                        host_kb_light_off ((~cmd_code)&0x7);
#endif
			}
			break;
		case SET_RATE_DELAY_SEQUENCE:
#ifndef NTVDM	/* JonLe Mod */
			if ((cmd_code & 0x80)==0)
			{
			repeat_delay_target = (1+((cmd_code>>5)&3))*BASE_DELAY_UNIT;
			cmd_code &= 0x1f;
			if (cmd_code<0xb) { repeat_target =0; }
			else { if (cmd_code<0x11) { repeat_target =1; }
			else { if (cmd_code<0x19) { repeat_target=(cmd_code-0x12)/3 +3;}
			else { if (cmd_code<0x1e) { repeat_target=(cmd_code-0x1a)/2+6;}
			else { repeat_target=(cmd_code-0x1e)+8;}}}}
                        AddTo6805BuffImm(ACK_CODE);
			}
			sure_note_trace2(AT_KBD_VERBOSE,"Changing kbd rate/delay: rate = %d, dealy=%d ",repeat_target,repeat_delay_target);

#else	/* NTVDM */

			if ((cmd_code & 0x80)==0)
			{
                        AddTo6805BuffImm(ACK_CODE);
			}

#endif	/* NTVDM */
			break;
		}
		waiting_for_next_code = FALSE;
	}
	else
	{

#endif /* not REAL_KBD */

	/*
	** Mac MPW3 compiler does not like bytes sized switch
	** variables if a case matches on 0xff. It seems to
	** generate dodgy code. Different type seems OK.
	*/
	cmd_code_temp = (unsigned int)cmd_code;
	switch ( cmd_code_temp )
	{
#ifndef REAL_KBD
	case 0xf5:
		/* Default Disable */
		clear_buff_6805 ();
                AddTo6805BuffImm(ACK_CODE);
		for (key_to_change=1;key_to_change<127;key_to_change++)
			{
			set_3_key_state[key_to_change]=set_3_default_key_state[key_to_change];
			}

#ifndef NTVDM 	/* JonLe NTVDM Mod */
		repeat_delay_target=2*BASE_DELAY_UNIT;
		repeat_target=DEFAULT_REPEAT_TARGET;
		typematic_key_valid=FALSE;
#endif	/* NTVDM */

		keyboard_disabled=TRUE;
		sure_note_trace0(AT_KBD_VERBOSE,"Keyboard disabled");
		break;
	case 0xee:
		/* echo */
                AddTo6805BuffImm(0xee);
		break;
	case 0xf4:
		/* enable */
		clear_buff_6805 ();
                AddTo6805BuffImm(ACK_CODE);

#ifndef NTVDM 	/* JonLe NTVDM Mod */
		typematic_key_valid=FALSE;
#endif	/* NTVDM */

		keyboard_disabled=FALSE;
		sure_note_trace0(AT_KBD_VERBOSE,"Keyboard enabled");
		break;
#endif
	case 0xf2:
		/* Read ID */
		/* order of reception of scan codes is reverse their order of insertion
		 * if 'IMMEDIATE_OUTPUT' method of insertion is used
		 */
                AddTo6805BuffImm(0x83);
                AddTo6805BuffImm(0xab);
                AddTo6805BuffImm(ACK_CODE);
		break;
	case 0xfe:
		/* resend */
		buff_6805_out_ptr=(buff_6805_out_ptr-1) & BUFF_6805_PMASK;
		calc_buff_6805_left();
		break;
#ifndef REAL_KBD
	case 0xff:
		/* reset */
		/* order of reception of scan codes is reverse their order of insertion
		 * if 'IMMEDIATE_OUTPUT' method of insertion is used
		 */
                AddTo6805BuffImm(BAT_COMPLETION_CODE);
                AddTo6805BuffImm(ACK_CODE);
		keyboard_disabled=FALSE;
		sure_note_trace0(AT_KBD_VERBOSE,"Keyboard reset");
		break;
	case 0xf0:
		/* Select Alternate Scan Codes */
		clear_buff_6805 ();
                AddTo6805BuffImm(ACK_CODE);

#ifndef NTVDM 	/* JonLe NTVDM Mod */
		typematic_key_valid=FALSE;
#endif	/* NTVDM */

		next_code_sequence_number=SCAN_CODE_CHANGE_SEQUENCE;
		held_event_count=0;
		scanning_discontinued = waiting_for_next_code=TRUE;
		break;
	case 0xf7:
	case 0xf8:
	case 0xf9:
	case 0xfa:
		/* Set all keys */
                AddTo6805BuffImm(ACK_CODE);
		change_to=cmd_code - 0xf6;
		for (key_to_change=1;key_to_change<127;key_to_change++)
			{
			set_3_key_state[key_to_change]=change_to;
			}
		sure_note_trace1(AT_KBD_VERBOSE,"All keys set to type :0x%x",change_to);
		break;
	case 0xf6:
		/* Set Default */
		clear_buff_6805 ();
                AddTo6805BuffImm(ACK_CODE);
		for (key_to_change=1;key_to_change<127;key_to_change++)
			{
			set_3_key_state[key_to_change]=set_3_default_key_state[key_to_change];
			}

#ifndef NTVDM 	/* JonLe NTVDM Mod */
		repeat_delay_target=2*BASE_DELAY_UNIT;
		repeat_target=DEFAULT_REPEAT_TARGET;
		typematic_key_valid=FALSE;
#endif	/* NTVDM */
		keyboard_disabled=FALSE;
		sure_note_trace0(AT_KBD_VERBOSE,"Keyboard set to default (and enabled)");
		break;
	case 0xfb:
	case 0xfc:
	case 0xfd:
		/* Set key type */
		clear_buff_6805 ();
                AddTo6805BuffImm(ACK_CODE);

#ifndef NTVDM 	/* JonLe NTVDM Mod */
		typematic_key_valid=FALSE;
#endif	/* NTVDM */

		next_code_sequence_number=SET_3_KEY_TYPE_SET_SEQUENCE;
		held_event_count=0;
		scanning_discontinued = waiting_for_next_code=TRUE;
		set_3_key_type_change_dest=cmd_code - 0xfa;
		break;
	case 0xed:
		/* Set/Reset Status Indicators */
                AddTo6805BuffImm(ACK_CODE);
		next_code_sequence_number=SET_STATUS_INDICATORS_SEQUENCE;
		held_event_count=0;
		scanning_discontinued = waiting_for_next_code=TRUE;
		break;
	case 0xf3:
		/* Set typematic Rate/Delay */
                AddTo6805BuffImm(ACK_CODE);
		next_code_sequence_number=SET_RATE_DELAY_SEQUENCE;
		held_event_count=0;
		scanning_discontinued = waiting_for_next_code=TRUE;
		break;
	default :
		/* unrecognised code */
                AddTo6805BuffImm(RESEND_CODE);
#else
	default :
		/* cmd to be sent on to real kbd */
		send_to_real_kbd(cmd_code);
#endif
	} /* end of switch */
#ifndef REAL_KBD
}
#else
	waiting_for_next_code=FALSE;
#endif

#ifndef REAL_KBD
if (scanning_discontinued && !waiting_for_next_code)
	{
	if (held_event_count != 0)
		{
		for (i=0;i<held_event_count;i++)
			{
			switch (held_event_type[i])
				{
				case KEY_DOWN_EVENT:
					do_host_key_down(held_event_key[i]);
					break;
				case KEY_UP_EVENT:
					do_host_key_up(held_event_key[i]);
					break;
				}
			}
		}
	scanning_discontinued=FALSE;
	}
#endif

#ifndef NTVDM
if (free_6805_buff_size < BUFF_6805_VMAX) 
	{
	codes_to_translate();
        }
#endif

} /* end of cmd_to_6805 */

/* interface to interrupts */

#ifdef NTVDM    /* JonLe NTVDM Mod */



/* KbdIntDelay
 *
 * UNDER ALL CONDITIONS we must provide a SAFE key rate that 16 bit apps
 * can handle. This must be done without looking at the bios buffer,
 * since not all apps use the bios int 9 handler.
 *
 */

LOCAL VOID KbdIntDelay(VOID)
{
       //
       // Wait until the kbd scancode has been read,
       // before invoking the next interrupt.
       //
   if (bKbdEoiPending)
       return;


   if (int_enabled) {
       bKbdEoiPending = TRUE;

       if ( (bBiosBufferSpace && !bKbdIntHooked) ||
            (!bForceDelayInts &&  KbdHdwFull <= 3)) {
           kbd_status |= 1;
           ica_hw_interrupt(KEYBOARD_INT_ADAPTER, KEYBOARD_INT_LINE, 1);
           }
       else {
           ULONG ulDelay;

           if (KbdHdwFull < 8 && bBiosBufferSpace) {
               ulDelay = 10000;
               }
           else if (KbdHdwFull < 16 && bBiosBufferSpace) {
               ulDelay = 15000;
               }
           else if (bPifFastPaste) {
               ulDelay = 20000;
               }
           else {
               ulDelay = 25000;
               }

           bDelayIntPending = TRUE;
           host_DelayHwInterrupt(KEYBOARD_INT_LINE,
                                 1,
                                 ulDelay
                                 );
           }

       HostIdleNoActivity();
       }
}



//This function is called by the ICA with the ica lock
void KbdEOIHook(int IrqLine, int CallCount)
{

   if (!bKbdEoiPending)  // sanity
       return;

   if (!bBiosOwnsKbdHdw && WaitKbdHdw(0xffffffff))  {
       bKbdEoiPending = FALSE;
       return;
       }

   bKbdIntHooked = KbdInt09Off == *(word *)(Start_of_M_area+0x09*4) &&
                   KbdInt09Seg == *(word *)(Start_of_M_area+0x09*4+2);

   bBiosBufferSpace = bBiosOwnsKbdHdw &&
                (bios_buffer_size() < (bPifFastPaste ? 8 : 4));

   output_full = FALSE;
   bKbdEoiPending = FALSE;

   bForceDelayInts = TRUE;
   continue_output();
   bForceDelayInts = FALSE;

   if (!bBiosOwnsKbdHdw)
        HostReleaseKbd();
}





LOCAL VOID do_q_int(char scancode)
{
   output_full = TRUE;
   output_contents = scancode;

   KbdIntDelay();
}


#else   /* NTVDM */

LOCAL VOID do_int IFN1(int,scancode)
{
	output_contents = (char)scancode;
	kbd_status |= 1;
	if (int_enabled)
	{
                sure_note_trace0(AT_KBD_VERBOSE,"keyboard interrupting");
                ica_hw_interrupt(KEYBOARD_INT_ADAPTER, KEYBOARD_INT_LINE, 1);
	}
}

LOCAL VOID do_q_int IFN1(char,scancode)
{
	output_full = TRUE;
#ifdef	DELAYED_INTS
	do_int ((int) scancode);
#else
	add_q_event_i( do_int, HOST_KEYBA_INST_DELAY, (int) scancode);
#endif	/* DELAYED_INTS */
}


/* typematic keyboard repeats */

GLOBAL VOID do_key_repeats IFN0()
{
#ifndef REAL_KBD
if (typematic_key_valid)
	{
	if (repeat_count==repeat_target && repeat_delay_count==repeat_delay_target)
		{
		scan_code_6805_size=make_sizes[keytypes[typematic_key]];
		scan_code_6805_array=make_arrays[typematic_key];
		add_codes_to_6805_buff(scan_code_6805_size,scan_code_6805_array);
		codes_to_translate ();
		repeat_count=0;
		}
	else
		{
		if (repeat_delay_count==repeat_delay_target)
			{
			repeat_count++;
			}
		else
			{
			repeat_delay_count++;
			}
		}
	}
#endif
    if (key_delay == 1)	/* a previous fill of the buffer was delayed by a dubious read of 0x60 */
      continue_output();
    if (key_delay)
      key_delay--;	/* count delay down */
} /* end of do_key_repeats */

#endif	/* NTVDM */


LOCAL VOID cmd_to_8042  IFN1(half_word,cmd_code)
{
int code_to_send,code_to_send_valid;

sure_note_trace1(AT_KBD_VERBOSE,"8042 received cmd:0x%x",cmd_code);

code_to_send_valid = FALSE;
if (waiting_for_next_8042_code)
	{
	switch (next_8042_code_sequence_number)
		{
		case WRITE_8042_CMD_BYTE_SEQUENCE:
			if ( (kbd_status & 0x8) == 0)
				{
				cmd_byte_8042=cmd_code;
				if ( (cmd_byte_8042 & 0x40) == 0)
					{
					translating=FALSE;
					}
				else
					{
					translating=TRUE;
					}
				if ( (cmd_byte_8042 & 0x20) != 0 || (cmd_byte_8042 & 0x10) != 0)
					{
					keyboard_interface_disabled=TRUE;
					}
				else
					{
					keyboard_interface_disabled=FALSE;
					}
				kbd_status &= 0xfb;
				kbd_status |= cmd_byte_8042 & 0x4;
				if ((cmd_byte_8042 & 1) == 0)
					{
					int_enabled=FALSE;
					}
				else
					{
					int_enabled=TRUE;
					}
				}
			else
				{
				waiting_for_next_8042_code=FALSE;
				}
			break;
		case WRITE_8042_OUTPUT_PORT_SEQUENCE:
			if ( (kbd_status & 0x8) == 0)
				{
				if ( (cmd_code & 1) == 0)
					{
					host_error(EG_CONT_RESET,ERR_QUIT | ERR_RESET,NULL);
					}
				if ( (cmd_code & 2) == 2)
					{
#ifdef PM
				   if ( !gate_a20_status )
				      {
#ifdef NTVDM
				      /* call xms function to deal with A20 */
				      xmsDisableA20Wrapping();
#else
				      sas_disable_20_bit_wrapping();
#endif /* NTVDM */
				      gate_a20_status = 1;
					}
				   }
				else
				   {
				   if ( gate_a20_status )
				      {
#ifdef NTVDM
				      xmsEnableA20Wrapping();
#else
				      sas_enable_20_bit_wrapping();
#endif /* NTVDM */
				      gate_a20_status = 0;
				      }
#else
				   host_error(EG_GATE_A20,ERR_QUIT | ERR_RESET | ERR_CONT,NULL);
#endif /* PM */
				   }
				if ( (cmd_code & 0x10) == 0)
					{
					int_enabled=FALSE;
					}
				else
					{
					int_enabled=TRUE;
					}
#ifdef PM
				op_port_remembered_bits=cmd_code & 0x2e;
#else
				op_port_remembered_bits=cmd_code & 0x2c;
#endif /* PM */
				}
			else
				{
				waiting_for_next_8042_code=FALSE;
				}
			break;
		} /* end of switch */
	}

if (!waiting_for_next_8042_code)
	{
	switch (cmd_code)
		{
		case 0x20:
			/* Read cmd byte */
			code_to_send=cmd_byte_8042;
			code_to_send_valid=TRUE;
			break;
		case 0x60:
			/* Write cmd byte */
			waiting_for_next_8042_code=TRUE;
			next_8042_code_sequence_number=WRITE_8042_CMD_BYTE_SEQUENCE;
			break;
		case 0xaa:
			/* Self Test (always returns 'pass') */
			code_to_send=0x55;
			code_to_send_valid=TRUE;
			break;
		case 0xab:
			/* Interface Test (always returns 'pass') */
			code_to_send=0x00;
			code_to_send_valid=TRUE;
			break;
		case 0xad:
			/* Disable keyboard interface */
			cmd_byte_8042 |= 0x10;
			keyboard_interface_disabled=TRUE;
			break;
		case 0xae:
			/* Enable keyboard interface */
			cmd_byte_8042 &= 0xef;
			if ((cmd_byte_8042 & 0x20) == 0)
				{
				keyboard_interface_disabled=FALSE;
				}
			break;
		case 0xc0:
			/* Read Input Port */
			code_to_send=input_port_val;
			code_to_send_valid=TRUE;
			break;
		case 0xd0:
			/* Read Output Port */
			code_to_send=0xc1 + op_port_remembered_bits;
			code_to_send_valid=TRUE;
			break;
		case 0xd1:
			/* Write to Output Port */
			waiting_for_next_8042_code=TRUE;
			next_8042_code_sequence_number=WRITE_8042_OUTPUT_PORT_SEQUENCE;
			break;
		case 0xe0:
			/* Read Test Input */
			code_to_send=0x02;
			code_to_send_valid=TRUE;
			break;
		case 0xf0:
		case 0xf1:
		case 0xf2:
		case 0xf3:
		case 0xf4:
		case 0xf5:
		case 0xf6:
		case 0xf7:
		case 0xf8:
		case 0xf9:
		case 0xfa:
		case 0xfb:
		case 0xfc:
		case 0xfd:
		case 0xfe:
                case 0xff:
#ifndef MONITOR
/*
 *  For reasons which I don't understand the monitor never
 *  did emulate the cpu_interrupt - HW_RESET in pr 1.0.
 *  and still doesn't in 1.0a. although maybe it should
 *  do something. Note this is required for 286 style pm.
 *  06-Dec-1993 Jonle
 *
 */

			/* Pulse Output Port bits */
			if ((cmd_code & 1) == 0)
                                {
                                /* pulse the reset line */
#ifdef PM
#ifndef NTVDM
                                reset_was_by_kbd = TRUE;
#endif
#ifdef CPU_30_STYLE
                                cpu_interrupt(CPU_HW_RESET, 0);
#else /* CPU_30_STYLE */
				cpu_interrupt_map |= CPU_RESET_EXCEPTION_MASK;
				host_cpu_interrupt();
#endif /* CPU_30_STYLE */
#endif
                                sure_note_trace0(AT_KBD_VERBOSE,"CPU RESET via keyboard");
                                }
#endif
			break;
		} /* end of switch */
	}
else
	{
	waiting_for_next_8042_code=FALSE;
	}
if (code_to_send_valid)
        {
#ifdef NTVDM
        //
        //  force filling of Kbd data port just like the real kbd
        //  since we no longer clear output_full in the Kbd_inb routine
        //
        output_full = FALSE;
        KbdData = -1;
#else
        if (!output_full)
		{
		do_q_int(code_to_send);
		}
	else
		{
		pending_8042=TRUE;
		pending_8042_value=code_to_send;
                }
#endif
        }

} /* end of cmd_to_8042 */




LOCAL half_word translate_6805_8042 IFN0()
{

half_word first_code,code;

/* performs the translation on scan codes which is done by the
   8042 keyboard controller in a real XT286 */

first_code=remove_from_6805_buff();

if (translating)
	{
	sure_note_trace1(AT_KBD_VERBOSE,"translating code %#x",first_code);
	if (first_code==0xf0)
		{
		if (free_6805_buff_size<BUFF_6805_VMAX) {
			code=remove_from_6805_buff();
			sure_note_trace1(AT_KBD_VERBOSE,"translating code %#x",code);
			if ((code != 0xfa) && (code != 0xfe)) {
				code=trans_8042[code]+0x80;
			}
			else {
				waiting_for_upcode=TRUE;
			}
			sure_note_trace1(AT_KBD_VERBOSE,"translated to %#x",code);
			waiting_for_upcode=FALSE;
			}
		else {
			waiting_for_upcode=TRUE;
			}
		}
	else
		{
		code=trans_8042[first_code];
		if (waiting_for_upcode) {
			if ((code !=0xfa) &&(code != 0xfe)){
				code+=0x80;
				waiting_for_upcode=FALSE;
			}
		}
		sure_note_trace1(AT_KBD_VERBOSE,"translated to %#x",code);
		}
	}
else
	{
	code=first_code;
	}
return (code);
} /* end of translate_6805_8042 */

#ifdef HUNTER
/*
** Put a scan code into the 8042 single char buffer.
** Called from do_hunter() in hunter.c
*/

#define HUNTER_REJECTED_CODES_LIMIT 100

int hunter_codes_to_translate IFN1( half_word, scan_code )
{
	LOCAL ULONG rejected_scan_codes = 0;

	sure_note_trace1(HUNTER_VERBOSE,"Requesting scan=%d",scan_code);

	if (!pending_8042 && !keyboard_interface_disabled && !output_full)
	{
		do_q_int(scan_code);
		sure_note_trace1( HUNTER_VERBOSE, "Accepted scan=%d", scan_code );

		rejected_scan_codes = 0;

		return( TRUE );
	}
	else
	{
		sure_note_trace0( HUNTER_VERBOSE, "Rejected scan" );

		if( rejected_scan_codes++ > HUNTER_REJECTED_CODES_LIMIT )
		{
			printf( "Application hung up - not reading scan codes\n" );
			printf( "Trapper terminating\n" );

			terminate();
		}

		return( FALSE );
	}
} /* end of hunter_codes_to_translate() */

#endif /* HUNTER */

/*
** Returns number of chars in buffer.
** As buffer is quite small there can either be 1 char or none in it.
*  This needs to be global for HUNTER, but only needs be local otherwise.
*/
#ifdef HUNTER
GLOBAL INT
#else
LOCAL INT
#endif
buffer_status_8042 IFN0()
{
	if (!pending_8042 && !keyboard_interface_disabled && !output_full)
		return( 0 );
	else
		return( 1 );
} /* END 8042_buffer_status() */

LOCAL VOID codes_to_translate  IFN0()
{
	char tempscan;

while (!pending_8042 && (free_6805_buff_size < BUFF_6805_VMAX) && !keyboard_interface_disabled && !output_full)
	{
		tempscan= translate_6805_8042();
		if (!waiting_for_upcode) {
			do_q_int(tempscan);
		}
	}
} /* end of codes_to_translate */

/* Thanks to Jonathan Lew of MS for code tidyup in this fn */
GLOBAL VOID continue_output IFN0()
{
char tempscan;

#ifdef NTVDM
if (bKbdEoiPending || keyboard_interface_disabled) {
    return;
    }
#endif


if(!output_full)
	{
	if (pending_8042)
		{
                pending_8042=FALSE;
                do_q_int(pending_8042_value);
		}
	else
		{
		if ((free_6805_buff_size < BUFF_6805_VMAX) && (!keyboard_interface_disabled))
			{
			tempscan=translate_6805_8042();
                        if (!waiting_for_upcode) {
                                do_q_int(tempscan);
                                }
			}
		}
        }
#ifdef NTVDM
else
    KbdIntDelay();
#endif

} /* end of continuous_output */


#ifdef NTVDM

/*  NT port:
 *  the host (nt_event.c) calls this to notify that
 *  it is resuming after blocking, to do any reinitialization
 *  necessary
 *
 *  - resets kbd flow regulators
 */
GLOBAL VOID KbdResume(VOID)
{
    WaitKbdHdw(0xffffffff);
    bKbdEoiPending = FALSE;
    bKbdIntHooked = FALSE;
    bBiosBufferSpace = TRUE;
    if (!keyboard_interface_disabled && output_full)
        KbdIntDelay();
    HostReleaseKbd();
}
#endif	/* NTVDM */

GLOBAL VOID kbd_inb IFN2(io_addr,port,half_word *,val)
{

#ifdef NTVDM    /* JonLe NTVDM Mod */

     if (!bBiosOwnsKbdHdw && WaitKbdHdw(0xffffffff))  {
         return;
         }


     if (!(DelayIrqLine & 0x2) || KbdData == -1) {
         if (bDelayIntPending) {
             bDelayIntPending = FALSE;
             kbd_status |= 1;
             }
         KbdData = output_contents;
         }


#endif

port &= 0x64;

if (port==0x64)
	{
        *val=kbd_status;
        }
else

#ifdef NTVDM	/* JonLe NTVDM Mod */

        {

        *val=KbdData;
        kbd_status &= 0xfe;

        //Sloppy keyboard fix is not needed for the NT port. An EOI
        //hook is used to control priming of the adapter.

        }

     if (!bBiosOwnsKbdHdw)
         HostReleaseKbd();

#else	/* NTVDM */

	{

        *val=output_contents;



        output_full=FALSE;


        kbd_status &= 0xfe;

        sure_note_trace1(AT_KBD_VERBOSE,"scan code read:0x%x",*val);



        /* the following is to cope with programs that read this port, then call the BIOS expecting it to still be readable,
	we detect such sloppy reads by their not disabling the keyboard interface first, and delay refilling the buffer for
        two timer ticks */
        if (keyboard_interface_disabled || key_delay)
		{ key_delay = 0; continue_output(); }
	else
                {
                         key_delay = 2;
/* May need quick event here to recheck key_delay & then continue_output */
                }
        }
#endif	/* NTVDM */

} /* end of kbd_inb */

GLOBAL VOID kbd_outb IFN2(io_addr,port,half_word,val)
{

#ifdef NTVDM
     if (!bBiosOwnsKbdHdw && WaitKbdHdw(0xffffffff))
     {
         return;
     }
#endif  /* NTVDM */

        port &= 0x64;
	if (port == 0x64)
	{
		kbd_status |= 0x08;
		cmd_to_8042(val);
	}
	else
	{
		cmd_byte_8042 &= 0xef;
		if ( !(cmd_byte_8042 & 0x20) )
			keyboard_interface_disabled=FALSE;

		kbd_status &= 0xf7;
		if (waiting_for_next_8042_code) 
			cmd_to_8042(val);
		else
			cmd_to_6805(val);
	}

#ifndef NTVDM	/* JonLe NTVDM Mod */

       if (free_6805_buff_size < BUFF_6805_VMAX)
            codes_to_translate();

#else   /* NTVDM */

        bForceDelayInts = TRUE;
        continue_output();
        bForceDelayInts = FALSE;

        if (!bBiosOwnsKbdHdw)
             HostReleaseKbd();

#endif	/* NTVDM */

} /*end of kbd_outb */


#ifndef NTVDM
/* Nothing seems to call this. I've no idea why it's here ... Simion */
/* I have been assured that these functions are used by sun - gvdl */

GLOBAL int status_6805_buffer IFN0()
{
	int	free_space;

	free_space = BUFF_6805_VMAX-
		((buff_6805_in_ptr - buff_6805_out_ptr) & BUFF_6805_PMASK);
	if (free_space<0) 
	{
		free_space=0;
		sure_note_trace0(AT_KBD_VERBOSE,"Keyboard buffer full");
	}
	return(free_space);
}


/*
 * Name: read_6805_buffer_variables
 *
 * Purpose:	To allow the host to access the state of the 6805 buffer
 *		This means eg. on Sun that cut/paste can be optimised.
 *
 * Output:	*in_ptr - value of the 6805 start pointer.
 * Output:	*out_ptr - value of the 6805 end pointer.
 * Output:	*buf_size - value of the 6805 buffer size.
 */
GLOBAL void read_6805_buffer_variables IFN3(
int	*, in_ptr,
int	*, out_ptr,
int	*, buf_size)
{
	*in_ptr = buff_6805_in_ptr;
	*out_ptr = buff_6805_out_ptr;
	*buf_size = BUFF_6805_PMASK;
}

GLOBAL VOID insert_code_into_6805_buf IFN1(half_word,code)
{
	sure_note_trace1(AT_KBD_VERBOSE,"got real keyboard scan code : %#x",code);
	add_codes_to_6805_buff(1,&code);
	sure_note_trace1(AT_KBD_VERBOSE,"new free buf size = %#x",free_6805_buff_size);
	if (code != 0xf0) {
		codes_to_translate();
	}
}
#endif

#ifdef SEGMENTATION
/*
 * The following #include specifies the code segment into which this
 * module will by placed by the MPW C compiler on the Mac II running
 * MultiFinder.
 */
#include "SOFTPC_INIT.seg"
#endif

GLOBAL VOID AT_kbd_post IFN0()
{
        kbd_status = 0x14;
}

#ifndef NTVDM

GLOBAL VOID AT_kbd_init IFN0()
{
	int key,i;
	SHORT videoAdapt;

	sure_note_trace0(AT_KBD_VERBOSE,"AT Keyboard initialisation");

	videoAdapt = (ULONG) config_inquire(C_GFX_ADAPTER, NULL);

	buff_6805_out_ptr=0;
	clear_buff_6805 ();
	key_set=DEFAULT_SCAN_CODE_SET;
	current_light_pattern=0;
#ifdef REAL_KBD
	send_to_real_kbd(0xf6); /* set default */
	wait_for_ack_from_kb();
#endif
	host_kb_light_on (7);

#ifndef REAL_KBD
	for (key=0;key<127;key++)
	{
		set_3_key_state [key] = set_3_default_key_state [key];
		key_down_count[key]=0;
	}
	repeat_delay_target=2*BASE_DELAY_UNIT;
	repeat_target=DEFAULT_REPEAT_TARGET;
#endif
	typematic_key_valid = waiting_for_next_code = 
		waiting_for_next_8042_code=FALSE;
	shift_on = l_shift_on = r_shift_on=FALSE;
	ctrl_on = l_ctrl_on = r_ctrl_on=FALSE;
	alt_on = l_alt_on = r_alt_on=FALSE;
	waiting_for_upcode=FALSE;
	input_port_val=0xbf;
	if (videoAdapt == MDA || videoAdapt == HERCULES)
		input_port_val |= 0x40;
	kbd_status = 0x10;
	cmd_byte_8042=0x45;
	keyboard_disabled = keyboard_interface_disabled=FALSE;
	op_port_remembered_bits=0xc;

#ifdef PM
	if ( gate_a20_status )
	{
#ifdef NTVDM
		xmsEnableA20Wrapping();
#else
		sas_enable_20_bit_wrapping();
#endif /* NTVDM */
		gate_a20_status = 0;
	}
#endif

	pending_8042 = output_full = in_anomalous_state=FALSE;
	int_enabled = translating=TRUE;
	scanning_discontinued=FALSE;
	held_event_count=0;

	io_define_inb(AT_KEYB_ADAPTOR, kbd_inb);
	io_define_outb(AT_KEYB_ADAPTOR, kbd_outb);

	for (i=KEYBA_PORT_START;i<=KEYBA_PORT_END;i+=2)
		io_connect_port(i, AT_KEYB_ADAPTOR, IO_READ_WRITE);

#ifndef REAL_KBD
	init_key_arrays();
#endif

	host_kb_light_off (5);
	num_lock_on = TRUE;

	host_key_down_fn_ptr = host_key_down;
	host_key_up_fn_ptr = host_key_up;
	do_key_repeats_fn_ptr = do_key_repeats;

} /* end of AT_kbd_init */

#else	/* NTVDM */

GLOBAL VOID AT_kbd_init()
{
       int i;

       sure_note_trace0(AT_KBD_VERBOSE,"AT Keyboard initialisation");

       clear_buff_6805 ();
       key_set=2;

       i = 127;
       while (i--)
          set_3_key_state [i] = set_3_default_key_state [i];

       input_port_val=0xbf;
       kbd_status = 0x10;
       cmd_byte_8042=0x45;
       op_port_remembered_bits=0xc;

       int_enabled = translating = TRUE;

       io_define_inb(AT_KEYB_ADAPTOR, kbd_inb);
       io_define_outb(AT_KEYB_ADAPTOR, kbd_outb);

       for (i=KEYBA_PORT_START;i<=KEYBA_PORT_END;i+=2)
               io_connect_port(i, AT_KEYB_ADAPTOR, IO_READ_WRITE);

       init_key_arrays();

       num_lock_on = TRUE;
       host_key_down_fn_ptr = host_key_down;
       host_key_up_fn_ptr = host_key_up;

       //Register an EOI hook for the keyboard
       RegisterEOIHook(KEYBOARD_INT_LINE,KbdEOIHook);

} /* end of AT_kbd_init */
#endif	/* NTVDM */
