summaryrefslogtreecommitdiffstats
path: root/private/mvdm/softpc.new/base/keymouse/keybd_io.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/softpc.new/base/keymouse/keybd_io.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/mvdm/softpc.new/base/keymouse/keybd_io.c')
-rw-r--r--private/mvdm/softpc.new/base/keymouse/keybd_io.c2162
1 files changed, 2162 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/base/keymouse/keybd_io.c b/private/mvdm/softpc.new/base/keymouse/keybd_io.c
new file mode 100644
index 000000000..c3dc483ba
--- /dev/null
+++ b/private/mvdm/softpc.new/base/keymouse/keybd_io.c
@@ -0,0 +1,2162 @@
+#include "insignia.h"
+#include "host_def.h"
+/*
+ * SoftPC Revision 2.0
+ *
+ * File: : keybd_io.c
+ *
+ * Title : Bios Keyboard Interface function
+ *
+ * Sccs ID : @(#)keybd_io.c 1.35 06/27/95
+ *
+ * Description : This package contains a group of functions that provide
+ * a logical keyboard interface:
+ *
+ * keyboard_init() Initialise the keyboard interface.
+ * keyboard_int() Deal with a character from the keyboard
+ * and place them in the BIOS buffer.
+ * keyboard_io() User routine to read characters from
+ * the BIOS buffer.
+ * bios_buffer_size() How many chars in the buffer ?
+ *
+ * Author : Rod Macgregor / Henry Nash
+ *
+ * Modified : Jon Eyre / Jim Hatfield / Uncle Tom Cobbley and all
+ *
+ * Modfications : This module is now designed to be totally portable, it
+ * represents both the hardware and user interrupt interfaces.
+ * These two functions are provided by the routines
+ * keyboard_int & keyboard_io. The system will initialise
+ * itself by a call to keyboard_init.
+ *
+ * The user is expected to supply the following host dependent
+ * routines for this module, tagged as follows:-
+ *
+ * [HOSTSPECIFIC]
+ *
+ * host_alarm(duration)
+ * long int duration ;
+ * - ring the host's bell.
+ *
+ * host_kb_init() - any local initialisations required when
+ * keyboard_init is called.
+ *
+ * Removed calls to cpu_sw_interrupt and replaced with
+ * host_simulate
+ *
+ */
+
+#ifdef SCCSID
+static char SccsID[]="@(#)keybd_io.c 1.35 06/27/95 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_BIOS.seg"
+#endif
+
+
+/*
+ * O/S include files.
+ */
+#include <stdio.h>
+#include TypesH
+#include TimeH
+
+/*
+ * SoftPC include files
+ */
+#include "xt.h"
+#include CpuH
+#include "sas.h"
+#include "bios.h"
+#include "ios.h"
+#include "ppi.h"
+#include "keyboard.h"
+#include "timeval.h"
+#include "timer.h"
+#include "keyba.h"
+#include "ica.h"
+#ifndef PROD
+#include "trace.h"
+#endif
+
+#include "debug.h"
+#include "idetect.h"
+
+
+/*
+ * ============================================================================
+ * External routines
+ * ============================================================================
+ */
+
+/*
+ * ============================================================================
+ * Local static data and defines
+ * ============================================================================
+ */
+
+#define SHIFT_KEY_SIZE 8
+#define ALT_TABLE_SIZE 36
+
+/*
+ * lookup table to check if the scan code received is a shift key
+ */
+static sys_addr shift_keys;
+
+/*
+ * corresponding table to 'shift_keys' to set relevant bits in masks when
+ * shift scan code received
+ */
+static sys_addr shift_masks;
+
+/*
+ * next two tables give values of chars when control key depressed. First
+ * table (ctl_n_table) is for main keyboard values and second (ctl_f_table)
+ * is for the function keys and keypad.
+ */
+static sys_addr ctl_n_table;
+static sys_addr ctl_f_table;
+
+/*
+ * values of ascii keys dependiing on shift or caps states
+ */
+static sys_addr lowercase;
+static sys_addr uppercase;
+
+
+/*
+ * remapping of some keys when alt key depressed. note 1st ten are for
+ * keypad entries.
+ */
+static sys_addr alt_table;
+
+/* Add variables for all these entry points instead of the previously used
+ * defines. This allows modification of these entry points from a loaded
+ * driver, when the Insignia bios may not be in the loaded in the default
+ * or assumed location.
+ */
+
+#if defined(NTVDM) && defined(LOCAL)
+/*
+ * Make static fns and globals visible to win32 debuggers
+ */
+#undef LOCAL
+#define LOCAL
+#endif
+
+#ifndef GISP_SVGA
+LOCAL word int15_seg = RCPU_INT15_SEGMENT,
+ int15_off = RCPU_INT15_OFFSET;
+
+LOCAL word int1b_seg = KEYBOARD_BREAK_INT_SEGMENT,
+ int1b_off = KEYBOARD_BREAK_INT_OFFSET;
+
+LOCAL word int05_seg = PRINT_SCREEN_INT_SEGMENT,
+ int05_off = PRINT_SCREEN_INT_OFFSET;
+
+LOCAL word rcpu_nop_segment = RCPU_NOP_SEGMENT,
+ rcpu_nop_offset = RCPU_NOP_OFFSET;
+
+LOCAL word rcpu_poll_segment = RCPU_POLL_SEGMENT,
+ rcpu_poll_offset = RCPU_POLL_OFFSET;
+#else /* GISP_SVGA */
+/* If we are GISP_SVGA the segments will be variables anyway */
+#define int15_seg RCPU_INT15_SEGMENT
+LOCAL word int15_off = RCPU_INT15_OFFSET;
+
+#define int1b_seg KEYBOARD_BREAK_INT_SEGMENT
+LOCAL word int1b_off = KEYBOARD_BREAK_INT_OFFSET;
+
+#define int05_seg PRINT_SCREEN_INT_SEGMENT
+LOCAL word int05_off = PRINT_SCREEN_INT_OFFSET;
+
+#define rcpu_nop_segment RCPU_NOP_SEGMENT
+LOCAL word rcpu_nop_offset = RCPU_NOP_OFFSET;
+
+#define rcpu_poll_segment RCPU_POLL_SEGMENT
+LOCAL word rcpu_poll_offset = RCPU_POLL_OFFSET;
+#endif /* GISP_SVGA */
+
+#if defined(IRET_HOOKS) && defined(GISP_CPU)
+IMPORT VOID HostAllowKbdInt(); /* Allow keybd Ints without an IRET */
+#endif /* IRET_HOOKS && GISP_CPU */
+
+#ifdef NTVDM
+
+#include "error.h"
+
+GLOBAL word wait_int_seg = RCPU_WAIT_INT_SEGMENT;
+GLOBAL word wait_int_off = RCPU_WAIT_INT_OFFSET;
+GLOBAL word dr_type_seg = DR_TYPE_SEGMENT;
+GLOBAL word dr_type_off = DR_TYPE_OFFSET;
+GLOBAL sys_addr dr_type_addr = DR_TYPE_ADDR;
+/* Global var to indicate whether keyboard bios or hardware owns the keyboard mutex. */
+GLOBAL BOOL bBiosOwnsKbdHdw;
+IMPORT ULONG WaitKbdHdw(ULONG dwTimeOut);
+IMPORT VOID HostReleaseKbd();
+IMPORT VOID HostResetKbdNotFullEvent();
+IMPORT VOID HostSetKbdNotFullEvent();
+GLOBAL VOID TryKbdInt(VOID);
+IMPORT VOID ResumeTimerThread(VOID);
+IMPORT VOID WaitIfIdle(VOID);
+
+
+#define FREEKBDHDW() bBiosOwnsKbdHdw = \
+ ( bBiosOwnsKbdHdw ? HostReleaseKbd(), FALSE : FALSE )
+
+
+/* for optimizing timer hardware interrupt generation defined in timer.c */
+extern word TimerInt08Seg;
+extern word TimerInt08Off;
+extern word TimerInt1CSeg;
+extern word TimerInt1COff;
+extern word KbdInt09Seg;
+extern word KbdInt09Off;
+extern BOOL VDMForWOW;
+
+void Keyb16Request(half_word BopFnCode);
+
+/* optimizes 16 bit handler */
+extern word *pICounter;
+extern word *pCharPollsPerTick;
+extern word *pShortIdle;
+extern word *pIdleNoActivity;
+
+
+extern half_word * stream_io_buffer;
+extern word * stream_io_dirty_count_ptr;
+extern word stream_io_buffer_size;
+extern sys_addr stream_io_bios_busy_sysaddr;
+
+#else
+#define FREEKBDHDW() /* Nothing for conventional SoftPC */
+#endif /* NTVDM */
+
+/*
+ * Mix in global defined data as well.
+ */
+
+#ifndef GISP_SVGA
+GLOBAL word rcpu_int1C_seg = USER_TIMER_INT_SEGMENT;
+GLOBAL word rcpu_int1C_off = USER_TIMER_INT_OFFSET;
+
+GLOBAL word rcpu_int4A_seg = RCPU_INT4A_SEGMENT;
+GLOBAL word rcpu_int4A_off = RCPU_INT4A_OFFSET;
+#else /* GISP_SVGA */
+
+/* For GISPSVGA the segs will already be variables */
+#define rcpu_int1C_seg = USER_TIMER_INT_SEGMENT;
+GLOBAL word rcpu_int1C_off = USER_TIMER_INT_OFFSET;
+
+#define rcpu_int4A_seg = RCPU_INT4A_SEGMENT;
+GLOBAL word rcpu_int4A_off = RCPU_INT4A_OFFSET;
+#endif /* GISP_SVGA */
+
+GLOBAL word dummy_int_seg = 0;
+GLOBAL word dummy_int_off = 0;
+
+#ifdef NTVDM
+GLOBAL word int13h_vector_off;
+GLOBAL word int13h_vector_seg;
+GLOBAL word int13h_caller_off;
+GLOBAL word int13h_caller_seg;
+#endif /* NTVDM */
+
+#if defined(NTVDM) && defined(MONITOR)
+/*
+** Microsoft special.
+** These variables are set below in kb_setup_vectors(), to addresses
+** passed by NTIO.SYS via BOP 5F -> MS_bop_F() -> kb_setup_vectors()
+** Tim June 92.
+*/
+/*
+** New ntio.sys variables for video ROM matching. Tim August 92.
+*/
+GLOBAL word int10_seg=0;
+GLOBAL word int10_caller=0;
+GLOBAL word int10_vector=0; /* Address of native int 10*/
+GLOBAL word useHostInt10=0; /* var that chooses between host video ROM or BOPs */
+GLOBAL word babyModeTable=0; /* Address of small mode table lives in ntio.sys */
+GLOBAL word changing_mode_flag=0; /* ntio.sys var to indicate vid mode change */
+GLOBAL word vga1b_seg = 0;
+GLOBAL word vga1b_off = 0; /* VGA capability table normally in ROM */
+GLOBAL word conf_15_off = 0;
+GLOBAL word conf_15_seg = 0; /* INT15 config table normally in ROM */
+
+void printer_setup_table(sys_addr table_addr);
+
+#endif /* NTVDM & MONITOR */
+
+extern int soft_reset ; /* set for ctl-alt-dels */
+
+/*
+ * ============================================================================
+ * Local macros
+ * ============================================================================
+ */
+
+LOCAL VOID exit_from_kbd_int IPT0();
+
+/*
+ * Function to increment BIOS buffer pointers, returns new one
+ */
+LOCAL word inc_buffer_ptr IFN1(word, buf_p)
+{
+ buf_p += 2;
+ if (buf_p == sas_w_at_no_check(BIOS_KB_BUFFER_END))
+ buf_p = sas_w_at_no_check(BIOS_KB_BUFFER_START);
+
+ return buf_p;
+}
+
+
+
+
+
+/*
+ * ============================================================================
+ * Internal functions
+ * ============================================================================
+ */
+
+
+/*
+ * Routine to translate scan code pairs for standard calls
+ * Returns CF set if this scancode/char pair should be thrown away.
+ */
+LOCAL VOID translate_std IFN0()
+{
+ IU8 ah, al;
+ enum {dontSetCF, setCF0, setCF1} cfSet = dontSetCF;
+
+ ah = getAH();
+ al = getAL();
+
+ if ( ah == 0xE0 ) /* is it keypad enter or / */
+ {
+ if ( (al == 0x0D) || (al == 0x0A) )
+ setAH( 0x1C ); /* code is enter */
+ else
+ setAH( 0x35 ); /* must be keypad ' / ' */
+
+ cfSet = setCF0;
+ }
+ else
+ {
+ if ( ah > 0x84 ) /* is it an extended one */
+ cfSet = setCF1;
+ else
+ {
+ if( al == 0xF0 ) /* is it one of the 'fill ins' */
+ {
+ if ( ah == 0) /* AH = 0 special case */
+ cfSet = setCF0;
+ else
+ cfSet = setCF1; /* Delete me */
+ }
+ else
+ {
+ if ( (al == 0xE0) && (ah != 0) )
+ setAL( 0 ); /* convert to compatible output */
+
+ cfSet = setCF0;
+ }
+ }
+ }
+
+ if (cfSet != dontSetCF)
+ setCF(cfSet == setCF1);
+}
+
+
+static void translate_ext()
+/*
+ * Routine to translate scan code pairs for extended calls
+ */
+{
+ if ( (getAL() == 0xF0 ) && (getAH() != 0) )
+ setAL( 0 );
+}
+
+/*
+ * Send command or data byte to the keyboard and await for the acknowledgemnt
+ */
+
+/*
+ * Arbitrary retry limits - experiments suggest that we always succeed
+ * on the first try in a pure SoftWindows. A "real keyboard" version may
+ * be different.
+ */
+
+#define WAIT_RETRY 5
+#define RESEND_RETRY 3
+
+LOCAL VOID send_data IFN1(half_word, data)
+{
+ int resend_retry;
+ word CS_save, IP_save;
+ half_word var_kb_flag_2;
+
+ note_trace1(BIOS_KB_VERBOSE,"Cmd to kb i/o buff:0x%x",data);
+
+ /*
+ * Save CS:IP before calling a recursive CPU to handle the interrupt
+ * from the keyboard
+ */
+
+ CS_save = getCS();
+ IP_save = getIP();
+
+ /*
+ * Set the retry flag ( KB_FE ) to force outb() at least once. If
+ * we have real keyboard hardware this may get set again if the
+ * hardware didn't understand the command for some reason e.g.
+ * garbled by the serial line.
+ */
+
+ var_kb_flag_2 = sas_hw_at(kb_flag_2) | KB_FE;
+ resend_retry = RESEND_RETRY;
+
+ do
+ {
+ IBOOL resend_command;
+ int wait_retry;
+
+ resend_command = (var_kb_flag_2 & KB_FE) != 0;
+ wait_retry = WAIT_RETRY;
+
+ /* Clear resend, acknowledge and error flags */
+ var_kb_flag_2 &= ~(KB_FE + KB_FA + KB_ERR);
+
+ /*
+ * Update Intel memory with cleared down flags *BEFORE*
+ * the outb(), which may set the acknowledge flag, if we
+ * execute enough Intel due to virtualisation.
+ */
+
+ sas_store(kb_flag_2, var_kb_flag_2);
+
+ /* Do the outb if necessary */
+
+ if( resend_command )
+ {
+ outb(KEYBA_IO_BUFFERS, data);
+ }
+
+ /* Look for one of the flag bits to be set or time out */
+
+ while( !(var_kb_flag_2 & (KB_FA + KB_FE + KB_ERR))
+ && ( --wait_retry > 0 ))
+ {
+ /*
+ * Process interrupt from kb.
+ *
+ * Note for perplexed keyboard debuggers:
+ * Keyboard interrupts are delayed for a few
+ * Intel instructions using quick events. This
+ * means that the IRR from the above outb() may
+ * not be raised until we have done the following
+ * sub-CPU a few times.
+ */
+
+ setCS(rcpu_nop_segment);
+ setIP(rcpu_nop_offset);
+ host_simulate();
+
+ /* Re-read flag byte to see if anything has happened */
+
+ var_kb_flag_2 = sas_hw_at(kb_flag_2);
+ }
+
+ /* If we got an acknowledge we've succeeded */
+
+ if (var_kb_flag_2 & KB_FA)
+ break;
+
+ /* Set up error flag (in case this is the last retry) */
+
+ note_trace0(BIOS_KB_VERBOSE,"failed to get ack ... retry");
+ var_kb_flag_2 |= KB_ERR;
+ }
+ while( --resend_retry > 0 );
+
+ if (var_kb_flag_2 & KB_ERR)
+ {
+ note_trace0(BIOS_KB_VERBOSE,"no more retrys");
+
+ /* Write back flags with error bit set */
+
+ sas_store(kb_flag_2, var_kb_flag_2);
+ }
+
+ setCS(CS_save);
+ setIP(IP_save);
+}
+
+
+
+LOCAL VOID check_indicators IFN1(IBOOL, eoi)
+ /* end of interrupt flag - if set to non-zero */
+ /* 0x20 is written to port 0x20 */
+{
+ half_word indicators ;
+ half_word var_kb_flag_2;
+
+ /* move switch indicators to bits 0-2 */
+
+ indicators = (sas_hw_at_no_check(kb_flag) & (CAPS_STATE + NUM_STATE + SCROLL_STATE)) >> 4;
+
+ var_kb_flag_2 = sas_hw_at_no_check(kb_flag_2);
+ /* compare with previous setting */
+ if ((indicators ^ var_kb_flag_2) & KB_LEDS)
+ {
+ /* check if update in progress */
+ if( (var_kb_flag_2 & KB_PR_LED) == 0)
+ {
+ /* No update in progress */
+ var_kb_flag_2 |= KB_PR_LED;
+ sas_store_no_check(kb_flag_2, var_kb_flag_2);
+ if (eoi)
+ outb(0x20, 0x20);
+
+#if defined(NTVDM) || defined(GISP_CPU)
+ /*
+ * On the NT port we do not update the real kbd lights
+ * so we don't need to do communicate with the kbd hdw (keyba.c)
+ *
+ * If this ever changes for the NT port then do not use
+ * send_data which forces us to switch context back to
+ * 16 bit and waits for a reply. Do this with a direct
+ * call to the kbd Hdw
+ *
+ */
+
+ /* set kb flag up with new status */
+
+ var_kb_flag_2 = (var_kb_flag_2 & 0xf8) | indicators;
+ sas_store_no_check(kb_flag_2, var_kb_flag_2);
+#ifdef NTVDM
+ host_kb_light_on (indicators);
+#endif
+
+#ifdef GISP_CPU
+ /*
+ ** We do update an emulation of the keyboard lights but we don't
+ ** want to do it via send_data and switching back to 16-bit.
+ ** We call the host routines directly.
+ */
+ host_kb_light_on (indicators);
+ host_kb_light_off ((~indicators)&0x7);
+
+#endif /* GISP_CPU */
+#else /* not NTVDM nor GISP_CPU */
+
+ send_data(LED_CMD);
+
+ /* set kb flag up with new status */
+ var_kb_flag_2 = (sas_hw_at_no_check(kb_flag_2) & 0xf8) | indicators;
+ sas_store_no_check(kb_flag_2, var_kb_flag_2);
+
+ /* check error from previous send_data() */
+ if( (var_kb_flag_2 & KB_ERR) == 0)
+ {
+ /* No error */
+ send_data(indicators);
+
+ /* test for error */
+ if(sas_hw_at_no_check(kb_flag_2) & KB_ERR) {
+ /* error! */
+ note_trace0(BIOS_KB_VERBOSE,"got error sending change LEDs command");
+ send_data(KB_ENABLE);
+ }
+ }
+ else
+ /* error! */
+ send_data(KB_ENABLE);
+#endif /* NTVDM or GISP_CPU */
+
+ /* turn off update indicator and error flag */
+ sas_store_no_check (kb_flag_2, sas_hw_at_no_check(kb_flag_2) & ~(KB_PR_LED + KB_ERR));
+ }
+ }
+}
+
+/*
+ * ============================================================================
+ * External functions
+ * ============================================================================
+ */
+
+/*
+** called from hunter.c:do_hunter()
+** tells hunter about the BIOS buffer size so it will not over fill
+** the BIOS buffer
+** Used in no Time Stamp mode only.
+**
+** Also useful in host paste code to make sure keys are not pasted in too
+** fast.
+*/
+int bios_buffer_size IPT0()
+{
+ word buffer_head, buffer_tail;
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ note_trace2( BIOS_KB_VERBOSE, "BIOS kbd buffer head=%d tail=%d",
+ buffer_head, buffer_tail );
+ if( buffer_tail > buffer_head )
+ return( buffer_tail - buffer_head );
+ else
+ return( buffer_head - buffer_tail );
+}
+
+LOCAL VOID K26A IFN0()
+{
+ /* Interrupt Return */
+ outb(0x20, 0x20);
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+}
+
+LOCAL VOID K26 IFN0()
+{
+ /* Reset last char H.C. flag */
+ sas_store_no_check(kb_flag_3, sas_hw_at_no_check(kb_flag_3) & ~(LC_E0 + LC_E1));
+
+ /* (same as K26A()) */
+ outb(0x20, 0x20);
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+}
+
+
+#ifndef NTVDM
+
+LOCAL VOID INT15 IFN0()
+{
+ word saveCS, saveIP;
+
+ saveCS = getCS();
+ saveIP = getIP();
+
+ setCS(int15_seg);
+ setIP(int15_off);
+
+ host_simulate();
+
+ setCS(saveCS);
+ setIP(saveIP);
+}
+
+#else /* NTVDM */
+
+void INT15(void);
+word sp_int15_handler_seg = 0;
+word sp_int15_handler_off = 0;
+
+#endif /* NTVDM */
+
+#ifndef NTVDM
+#define BEEP(message) always_trace0(message); \
+ host_alarm(250000L); \
+ K26A()
+#else /* NTVDM */
+/* NTVDM code size is too large, change this often used macro
+ * to a function, as the call overhead is not justified
+ */
+void BEEP(char *message)
+{
+ note_trace0(BIOS_KB_VERBOSE,message);
+ host_alarm(250000L);
+ K26A();
+}
+#endif /* NTVDM */
+
+
+
+/*
+** Tell ICA End of Interrupt has happened, the ICA will
+** allow interupts to go off again.
+** Call INT 15.
+** Reenable the Keyboard serial line so Keyboard
+** interrupts can go off.
+** NOTE:
+** this is different to the real BIOS. The real BIOS
+** does ICA, Keyboard then INT 15, if we do that Keyboard
+** interrupts occur too soon, during the INT 15 and blow the
+** DOS stack. We effectively stop Keybd interrupts during the
+** INT 15.
+**
+** <tur 17-Jun-93> Take a leaf outta NTVDM's book and make these
+** functions rather than macros. (This reduced the size of keybd_io.c.o
+** on the Mac from 38K to 12K!) After all, it isn't as if keyboards are
+** highly speed sensitive!
+*/
+#ifndef NTVDM
+
+LOCAL VOID PutInBufferFunc IFN2(half_word, s, half_word, v)
+{
+ word buffer_head, buffer_tail, buffer_ptr;
+
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_ptr = inc_buffer_ptr(/* from: */buffer_tail);
+
+ if (buffer_ptr == buffer_head) {
+ BEEP("BIOS keyboard buffer overflow");
+ }
+ else {
+ sas_store_no_check(BIOS_VAR_START + buffer_tail, v);
+ sas_store_no_check(BIOS_VAR_START + buffer_tail+1, s);
+ sas_storew_no_check(BIOS_KB_BUFFER_TAIL, buffer_ptr);
+
+ outb(0x20, 0x20);
+ setAX(0x9102);
+ INT15();
+
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ sas_store (kb_flag_3, sas_hw_at(kb_flag_3) & ~(LC_E0 + LC_E1));
+ setIF(0);
+ }
+
+ exit_from_kbd_int();
+}
+
+
+#else /* NTVDM */
+
+
+/* <tur> NT's PutInBuffer seems to be slightly different to PutInBufferFunc above. */
+/* So I'm Not Touching it! (Is this a good expansion of "NT"? :-) */
+
+/* Our code size is too large, change this often used macro
+ * to a function, as the call overhead is not justified
+ */
+
+void NtPutInBuffer(half_word s, half_word v)
+{
+ word buffer_head, buffer_tail, buffer_ptr;
+
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_ptr = inc_buffer_ptr(/* from: */buffer_tail);
+
+ if (buffer_ptr == buffer_head) {
+ BEEP("BIOS keyboard buffer overflow");
+ }
+ else {
+ sas_store_no_check(BIOS_VAR_START + buffer_tail, v);
+ sas_store_no_check(BIOS_VAR_START + buffer_tail+1, s);
+ sas_storew_no_check(BIOS_KB_BUFFER_TAIL, buffer_ptr);
+ setAX(0x9102);
+ INT15();
+ K26();
+ setIF(0);
+ }
+
+ exit_from_kbd_int();
+}
+
+#define PUT_IN_BUFFER(s, v) NtPutInBuffer(s,v); return
+#endif /* NTVDM */
+
+
+/* <tur 17-Jun-93> Eurrgh; macros with embedded "return"s! */
+
+#ifndef NTVDM
+#define PUT_IN_BUFFER(s, v) PutInBufferFunc(s,v); return
+#endif /* !NTVDM */
+
+LOCAL VOID CheckAndPutInBufferFunc IFN2(half_word, s,half_word, v)
+{
+ if ((s == 0xff) || (v == 0xff)) {
+ K26();
+ exit_from_kbd_int();
+ }
+ else {
+#ifndef NTVDM
+ PutInBufferFunc(s, v);
+#else /* NTVDM */
+ NtPutInBuffer(s, v);
+#endif /* !NTVDM */
+ }
+}
+
+#define CHECK_AND_PUT_IN_BUFFER(s,v) CheckAndPutInBufferFunc(s, v); return
+
+
+LOCAL VOID PAUSE IFN0()
+{
+ word CS_save; /* tmp. store for CS value */
+ word IP_save; /* tmp. store for IP value */
+
+ sas_store_no_check(kb_flag_1, sas_hw_at_no_check(kb_flag_1) | HOLD_STATE);
+
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ outb(0x20, 0x20);
+
+ CS_save = getCS();
+ IP_save = getIP();
+
+ FREEKBDHDW();
+
+ do {
+#if defined(IRET_HOOKS) && defined(GISP_CPU)
+ HostAllowKbdInt(); /* Allow a keypress to generate an interrupt */
+#endif /* IRET_HOOKS && GISP_CPU */
+
+
+#if defined(NTVDM)
+ IDLE_waitio();
+#endif
+
+ setCS(rcpu_nop_segment);
+ setIP(rcpu_nop_offset);
+ host_simulate();
+
+ } while (sas_hw_at_no_check(kb_flag_1) & HOLD_STATE);
+
+ setCS(CS_save);
+ setIP(IP_save);
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+}
+
+#ifndef NTVDM
+static int re_entry_level=0;
+#endif
+
+/*
+** All exits from keyboard_int() call this first.
+*/
+LOCAL void exit_from_kbd_int IFN0()
+{
+#ifndef NTVDM
+ --re_entry_level;
+ if( re_entry_level >= 4 )
+ always_trace1("ERROR: KBD INT bad exit level %d", re_entry_level);
+#endif
+ note_trace0( BIOS_KB_VERBOSE, "KBD BIOS - END" );
+ setIF( 0 );
+ FREEKBDHDW(); /* JonLe NTVDM Mod */
+}
+
+void keyboard_int IFN0()
+{
+ int i; /* loop counter */
+
+ half_word code, /* scan code from keyboard */
+ code_save, /* tmp variable for above */
+ chr, /* ASCII char code */
+ last_kb_flag_3, /* kb_flag_3 saved */
+ mask;
+#ifdef NTVDM
+ word IP_save,
+ buffer_head, /* ptr. to head of kb buffer */
+ buffer_tail; /* ptr. to tail of kb buffer */
+ half_word BopFnCode;
+#endif /* NTVDM */
+
+
+
+ boolean upper; /* flag indicating upper case */
+
+#ifdef NTVDM
+ BopFnCode = getAH();
+ if (BopFnCode) {
+ Keyb16Request(BopFnCode);
+ return;
+ }
+#endif
+#ifndef NTVDM
+ ++re_entry_level;
+ if( re_entry_level > 4 ){
+ always_trace1("ERROR: KBD BIOS re-entered at level %d\n", re_entry_level-1);
+ }
+#endif
+ setIF(0);
+ note_trace0(BIOS_KB_VERBOSE,"KBD BIOS start");
+
+#ifdef NTVDM /* JonLe keyboard mod */
+ bBiosOwnsKbdHdw = !WaitKbdHdw(5000);
+#endif /* NTVDM */
+
+ /* disable keyboard */
+ outb(KEYBA_STATUS_CMD, DIS_KBD);
+
+#ifdef NTVDM
+ /*
+ * CarbonCopy traces int 9 in order to gain control
+ * over where the kbd data is coming from (the physical kbd
+ * or the serial link) The kbd_inb instruction must be visible
+ * in the 16 bit code via int 1 tracing, for CarbonCopy to work.
+ * interrupts should be kept off.
+ */
+ if (getTF()) {
+ IP_save = getIP();
+ setIP(IP_save + 4); /* adavance by 4 bytes, pop ax, jmp iret_com */
+ host_simulate();
+ setIP(IP_save);
+ code = getAL();
+ }
+ else
+#endif
+ inb(KEYBA_IO_BUFFERS, &code); /* get scan_code */
+
+ /* call recursive CPU to handle int 15 call */
+ setAH(0x4f);
+ setAL(code);
+ setCF(1); /* Default return says scan code NOT consumed - needed by Freelance Plus 3.01 */
+ INT15();
+ code = getAL(); /* suret int 15 function can change the scan code in AL */
+
+
+ if(!getCF()) /* check CF */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ if ( code == KB_RESEND ) /* check for resend */
+ {
+ sas_store_no_check (kb_flag_2, sas_hw_at_no_check(kb_flag_2) | KB_FE);
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ if( code == KB_ACK ) /* check for acknowledge */
+ {
+ sas_store_no_check (kb_flag_2, sas_hw_at_no_check(kb_flag_2) | KB_FA);
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ check_indicators(0);
+
+ if ( code == KB_OVER_RUN ) /* test for overrun */
+ {
+ BEEP("hardware keyboard buffer overflow");
+ exit_from_kbd_int();return;
+ }
+ last_kb_flag_3 = sas_hw_at_no_check(kb_flag_3);
+
+ /* TEST TO SEE IF A READ_ID IS IN PROGRESS */
+ if ( last_kb_flag_3 & (RD_ID + LC_AB) )
+ {
+ if ( sas_hw_at_no_check(kb_flag) & RD_ID ) /* is read_id flag on */
+ {
+ if( code == ID_1 ) /* is this the 1st ID char. */
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3) | LC_AB);
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3) & ~RD_ID);
+ }
+ else
+ {
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3) & ~LC_AB);
+ if( code != ID_2A ) /* is this the 2nd ID char. */
+ {
+ if( code == ID_2 )
+ {
+ /* should we set NUM LOCK */
+ if( last_kb_flag_3 & SET_NUM_LK )
+ {
+ sas_store_no_check (kb_flag, sas_hw_at_no_check(kb_flag) | NUM_STATE);
+ check_indicators(1);
+ }
+ }
+ else
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ }
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3) | KBX); /* enhanced kbd found */
+ }
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ if( code == MC_E0 ) /* general marker code? */
+ {
+ sas_store_no_check(kb_flag_3, sas_hw_at_no_check(kb_flag_3) | ( LC_E0 + KBX ));
+ K26A();
+ exit_from_kbd_int();return;
+ }
+
+ if( code == MC_E1 ) /* the pause key ? */
+ {
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check (kb_flag_3) | ( LC_E1 + KBX ));
+ K26A();
+ exit_from_kbd_int();return;
+ }
+
+ code_save = code; /* turn off break bit */
+ code &= 0x7f;
+
+ if( last_kb_flag_3 & LC_E0) /* last code=E0 marker? */
+ {
+ /* is it one of the shift keys */
+ if( code == sas_hw_at_no_check(shift_keys+6) || code == sas_hw_at_no_check(shift_keys+7) )
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ }
+ else if( last_kb_flag_3 & LC_E1 ) /* last code=E1 marker? */
+ {
+ /* is it alt, ctl or one of the shift keys */
+ if( code == sas_hw_at_no_check(shift_keys+4) || code == sas_hw_at_no_check(shift_keys+5) ||
+ code == sas_hw_at_no_check(shift_keys+6) || code == sas_hw_at_no_check(shift_keys+7) )
+ {
+ K26A();
+ exit_from_kbd_int();return;
+ }
+ if( code == NUM_KEY ) /* is it the pause key */
+ {
+ /* is it the break or are we paused already */
+ if( (code_save & 0x80) || (sas_hw_at_no_check(kb_flag_1) & HOLD_STATE) )
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ PAUSE();
+ exit_from_kbd_int();return;
+ }
+ }
+ /* TEST FOR SYSTEM KEY */
+ else if( code == SYS_KEY )
+ {
+ if( code_save & 0x80 ) /* check for break code */
+ {
+ sas_store_no_check(kb_flag_1, sas_hw_at_no_check(kb_flag_1) & ~SYS_SHIFT);
+ K26A();
+ /* call recursive CPU to call INT 15 */
+ setAX(0x8501);
+ INT15();
+ exit_from_kbd_int();return;
+ }
+ if( sas_hw_at_no_check(kb_flag_1) & SYS_SHIFT) /* Sys key held down ? */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ sas_store_no_check (kb_flag_1, sas_hw_at_no_check(kb_flag_1) | SYS_SHIFT);
+ K26A();
+ /* call recursive CPU to call INT 15 */
+ setAX(0x8500);
+ INT15();
+ exit_from_kbd_int();return;
+ }
+ /* TEST FOR SHIFT KEYS */
+ for( i=0; i < SHIFT_KEY_SIZE; i++)
+ if ( code == sas_hw_at_no_check(shift_keys+i) )
+ break;
+ code = code_save;
+
+ if( i < SHIFT_KEY_SIZE ) /* is there a match */
+ {
+ mask = sas_hw_at_no_check (shift_masks+i);
+ if( code & 0x80 ) /* test for break key */
+ {
+ if (mask >= SCROLL_SHIFT) /* is this a toggle key */
+ {
+ sas_store_no_check (kb_flag_1, sas_hw_at_no_check(kb_flag_1) & ~mask);
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ sas_store_no_check (kb_flag, sas_hw_at_no_check(kb_flag) & ~mask); /* turn off shift bit */
+ if( mask >= CTL_SHIFT) /* alt or ctl ? */
+ {
+ if( sas_hw_at_no_check (kb_flag_3) & LC_E0 ) /* 2nd alt or ctl ? */
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3) & ~mask);
+ else
+ sas_store_no_check (kb_flag_1, sas_hw_at_no_check(kb_flag_1) & ~(mask >> 2));
+ sas_store_no_check (kb_flag, sas_hw_at_no_check(kb_flag) | ((((sas_hw_at_no_check(kb_flag) >>2 ) | sas_hw_at(kb_flag_1)) << 2) & (ALT_SHIFT + CTL_SHIFT)));
+ }
+ if(code != (ALT_KEY + 0x80)) /* alt shift release ? */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ code = sas_hw_at_no_check(alt_input);
+ if ( code == 0 ) /* input == 0 ? */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+
+ sas_store_no_check(alt_input, 0); /* Zero the ALT_INPUT char */
+ /* At this point, the ALT input char (now in "code") should be put in the buffer. */
+ PUT_IN_BUFFER(0, code);
+#ifdef NTVDM
+ return;
+#endif
+ }
+ /* SHIFT MAKE FOUND, DETERMINE SET OR TOGGLE */
+ if( mask < SCROLL_SHIFT )
+ {
+ sas_store_no_check (kb_flag, sas_hw_at_no_check(kb_flag) | mask);
+ if ( mask & (CTL_SHIFT + ALT_SHIFT) )
+ {
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) /* one of the new keys ?*/
+ sas_store_no_check(kb_flag_3, sas_hw_at_no_check(kb_flag_3) | mask); /* set right, ctl alt */
+ else
+ sas_store_no_check (kb_flag_1,sas_hw_at_no_check(kb_flag_1) | (mask >> 2)); /* set left, ctl alt */
+ }
+ K26();
+ exit_from_kbd_int();return;
+ }
+ /* TOGGLED SHIFT KEY, TEST FOR 1ST MAKE OR NOT */
+ if( (sas_hw_at_no_check(kb_flag) & CTL_SHIFT) == 0 )
+ {
+ if( code == INS_KEY )
+ {
+ if( sas_hw_at_no_check(kb_flag) & ALT_SHIFT )
+ goto label1;
+
+ if( (sas_hw_at_no_check(kb_flag_3) & LC_E0) == 0 ) /* the new insert key ? */
+ {
+ /* only continue if NUM_STATE flag set OR
+ one or both of the shift flags */
+ if( ((sas_hw_at_no_check(kb_flag) &
+ (NUM_STATE + LEFT_SHIFT + RIGHT_SHIFT))
+ == NUM_STATE) ||
+ (((sas_hw_at_no_check(kb_flag) & NUM_STATE) == 0)
+ && (sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT))) )
+ goto label1;
+ }
+ }
+ /* shift toggle key hit */
+ if( mask & sas_hw_at_no_check(kb_flag_1) ) /* already depressed ? */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ sas_store_no_check (kb_flag_1, sas_hw_at_no_check(kb_flag_1) | mask); /* set and toggle flags */
+ sas_store_no_check ( kb_flag, sas_hw_at_no_check(kb_flag) ^ mask);
+ if( mask & (CAPS_SHIFT + NUM_SHIFT + SCROLL_SHIFT) )
+ check_indicators(1);
+
+ if( code == INS_KEY ) /* 1st make of ins key */
+ goto label2;
+
+ K26();
+ exit_from_kbd_int();return;
+ }
+ }
+label1: /* TEST FOR HOLD STATE */
+ if( code & 0x80 ) /* test for break */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ if( sas_hw_at_no_check(kb_flag_1) & HOLD_STATE ) /* in hold state ? */
+ {
+ if( code != NUM_KEY )
+ sas_store_no_check (kb_flag_1, sas_hw_at_no_check(kb_flag_1) & ~HOLD_STATE);
+ K26();
+ exit_from_kbd_int();return;
+ }
+label2: /* NOT IN HOLD STATE */
+ if( code > 88) /* out of range ? */
+ {
+ K26();
+ exit_from_kbd_int();return;
+ }
+ /* are we in alternate shift */
+ if( (sas_hw_at_no_check(kb_flag) & ALT_SHIFT) && ( ((sas_hw_at_no_check(kb_flag_3) & KBX) == 0) ||
+ ((sas_hw_at_no_check(kb_flag_1) & SYS_SHIFT) == 0) ) )
+ {
+ /* TEST FOR RESET KEY SEQUENCE (CTL ALT DEL) */
+ if( (sas_hw_at_no_check(kb_flag) & CTL_SHIFT ) && (code == DEL_KEY) )
+ {
+#ifndef NTVDM
+ reboot();
+#else
+ K26();
+#endif
+ exit_from_kbd_int();return;
+ }
+ /* IN ALTERNATE SHIFT, RESET NOT FOUND */
+ if( code == SPACEBAR )
+ {
+ PUT_IN_BUFFER(code, ' ');
+ }
+ if( code == TAB_KEY )
+ {
+ PUT_IN_BUFFER(0xa5, 0 ); /* special code for alt-tab */
+ }
+ if( (code == KEY_PAD_MINUS) || (code == KEY_PAD_PLUS) )
+ {
+ PUT_IN_BUFFER(code, 0xf0); /* special ascii code */
+ }
+ /* LOOK FOR KEYPAD ENTRY */
+ for (i = 0; i < 10; i++ )
+ if ( code == sas_hw_at_no_check (alt_table+i) )
+ break;
+ if( i < 10 )
+ {
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) /* one of the new keys ? */
+ {
+ PUT_IN_BUFFER((code + 80), 0 );
+ }
+ sas_store_no_check (alt_input, sas_hw_at_no_check(alt_input) * 10 + i);
+ K26();
+ exit_from_kbd_int();return;
+ }
+ /* LOOK FOR SUPERSHIFT ENTRY */
+ for( i = 10; i < ALT_TABLE_SIZE; i++)
+ if( code == sas_hw_at_no_check (alt_table+i))
+ break;
+ if( i < ALT_TABLE_SIZE )
+ {
+ PUT_IN_BUFFER(code, 0 );
+ }
+ /* LOOK FOR TOP ROW OF ALTERNATE SHIFT */
+ if( code < TOP_1_KEY )
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, 0xf0); /* must be escape */
+ }
+ if( code < BS_KEY )
+ {
+ PUT_IN_BUFFER((code + 118), 0);
+ }
+ /* TRANSLATE ALTERNATE SHIFT PSEUDO SCAN CODES */
+ if((code == F11_M) || (code == F12_M) ) /* F11 or F12 */
+ {
+ PUT_IN_BUFFER((code + 52), 0 );
+ }
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) /* one of the new keys ?*/
+ {
+ if( code == KEY_PAD_ENTER )
+ {
+ PUT_IN_BUFFER(0xa6, 0);
+ }
+ if( code == DEL_KEY )
+ {
+ PUT_IN_BUFFER(( code + 80), 0 );
+ }
+ if( code == KEY_PAD_SLASH )
+ {
+ PUT_IN_BUFFER(0xa4, 0);
+ }
+ K26();
+ exit_from_kbd_int();return;
+ }
+ if( code < F1_KEY )
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, 0xf0);
+ }
+ if( code <= F10_KEY )
+ {
+ PUT_IN_BUFFER( (code + 45), 0 );
+ }
+ K26();
+ exit_from_kbd_int();return;
+ }
+ /* NOT IN ALTERNATE SHIFT */
+ if(sas_hw_at_no_check(kb_flag) & CTL_SHIFT) /* control shift ? */
+ {
+ if( (code == SCROLL_KEY) && ( ((sas_hw_at_no_check(kb_flag_3) & KBX) == 0) || (sas_hw_at_no_check(kb_flag_3) & LC_E0) ) )
+ {
+ /* reset buffer to empty */
+ sas_storew_no_check(BIOS_KB_BUFFER_TAIL, sas_w_at_no_check(BIOS_KB_BUFFER_HEAD));
+
+ sas_store (bios_break, 0x80); /* turn on bios brk bit */
+ outb(KEYBA_STATUS_CMD, ENA_KBD); /* enable keyboard */
+
+ FREEKBDHDW(); /* JonLe NTVDM mod */
+
+ exec_sw_interrupt(int1b_seg, int1b_off);
+
+ PUT_IN_BUFFER(0, 0);
+ }
+ /* TEST FOR PAUSE */
+ if( ((sas_hw_at_no_check(kb_flag_3) & KBX) == 0) && (code == NUM_KEY))
+ {
+ PAUSE();
+ exit_from_kbd_int();return;
+ }
+ /* TEST SPECIAL CASE KEY 55 */
+ if( code == PRINT_SCR_KEY )
+ {
+ if ( ((sas_hw_at_no_check(kb_flag_3) & KBX) == 0) || (sas_hw_at_no_check(kb_flag_3) &LC_E0) )
+ {
+ PUT_IN_BUFFER(0x72, 0);
+ }
+ }
+ else
+ {
+ if( code != TAB_KEY )
+ {
+ if( (code == KEY_PAD_SLASH) && (sas_hw_at_no_check(kb_flag_3) & LC_E0) )
+ {
+ PUT_IN_BUFFER(0x95, 0 );
+ }
+ if( code < F1_KEY ) /* is it in char table? */
+ {
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check(ctl_n_table+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check(ctl_n_table+code - 1) );
+ }
+ }
+ }
+ }
+ chr = ( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) ? MC_E0 : 0;
+ CHECK_AND_PUT_IN_BUFFER(sas_hw_at_no_check(ctl_n_table+code - 1), chr);
+ }
+ /* NOT IN CONTROL SHIFT */
+
+ if( code <= CAPS_KEY )
+ {
+ if( code == PRINT_SCR_KEY )
+ {
+ if( ((sas_hw_at_no_check(kb_flag_3) & (KBX + LC_E0)) == (KBX + LC_E0)) ||
+ ( ((sas_hw_at_no_check(kb_flag_3) & KBX) == 0) && (sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT))) )
+ {
+ /* print screen */
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ outb(0x20, 0x20);
+
+ FREEKBDHDW(); /* JonLe NTVDM Mod */
+
+ exec_sw_interrupt(int05_seg, int05_off);
+
+ sas_store_no_check (kb_flag_3, sas_hw_at_no_check(kb_flag_3)& ~(LC_E0 + LC_E1));
+ exit_from_kbd_int();return;
+ }
+ }
+ else
+ {
+ if( ((sas_hw_at_no_check(kb_flag_3) & LC_E0) == 0) || (code != KEY_PAD_SLASH))
+ {
+ for( i = 10; i < ALT_TABLE_SIZE; i++ )
+ if(code == sas_hw_at_no_check(alt_table+i))
+ break;
+ /* did we find one */
+ upper = FALSE;
+ if( (i < ALT_TABLE_SIZE) && (sas_hw_at_no_check(kb_flag) & CAPS_STATE) )
+ {
+ if( (sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT)) == 0 )
+ upper = TRUE;
+ }
+ else
+ {
+ if( sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT) )
+ upper = TRUE;
+ }
+
+ if (upper)
+ {
+ /* translate to upper case */
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check(uppercase+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check (uppercase+code - 1) );
+ }
+ }
+ }
+ }
+ /* translate to lower case */
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check (lowercase+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check(lowercase+code - 1) );
+ }
+ }
+ /* TEST FOR KEYS F1 - F10 */
+ /* 7.10.92 MG AND TEST FOR F11 AND F12 !!!!
+ We were shoving the code for shift-F11 or shift-F12 in if
+ you pressed unshifted keys. This has been changed so that all the
+ function keys are handled the same way, which is the correct
+ procedure.
+ */
+
+ if( code > F10_KEY && (code != F11_KEY && code != F12_KEY) )
+ {
+ if( code > DEL_KEY )
+ {
+ if (code == WT_KEY )
+ {
+ if ( sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT) )
+ {
+ /* translate to upper case */
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check(uppercase+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check(uppercase+code - 1) );
+ }
+ }
+ else
+ {
+ /* translate to lower case */
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check(lowercase+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check(lowercase+code - 1) );
+ }
+ }
+ }
+ else
+ {
+ if( (code == 76) && ((sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT)) == 0))
+ {
+ PUT_IN_BUFFER( code, 0xf0);
+ }
+ /* translate for pseudo scan codes */
+ chr = ( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) ? MC_E0 : 0;
+
+ /* Should this always be upper case ???? */
+
+ CHECK_AND_PUT_IN_BUFFER(sas_hw_at_no_check (uppercase+code - 1), chr);
+ }
+ }
+ if (
+ (code == KEY_PAD_MINUS) ||
+ (code == KEY_PAD_PLUS) ||
+ ( !(sas_hw_at_no_check(kb_flag_3) & LC_E0) &&
+ (
+ ((sas_hw_at_no_check(kb_flag) & (NUM_STATE + LEFT_SHIFT + RIGHT_SHIFT)) == NUM_STATE) ||
+ (((sas_hw_at_no_check(kb_flag) & NUM_STATE) == 0) && (sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT)))
+ )
+ )
+ )
+ {
+ /* translate to upper case */
+ if( sas_hw_at_no_check(kb_flag_3) & LC_E0)
+ {
+ CHECK_AND_PUT_IN_BUFFER(MC_E0, sas_hw_at_no_check(uppercase+code - 1) );
+ }
+ else
+ {
+ CHECK_AND_PUT_IN_BUFFER(code, sas_hw_at_no_check(uppercase+code - 1) );
+ }
+ }
+ }
+ else
+ {
+ if( sas_hw_at_no_check(kb_flag) & (LEFT_SHIFT + RIGHT_SHIFT) )
+ {
+ /* translate for pseudo scan codes */
+ chr = ( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) ? MC_E0 : 0;
+ CHECK_AND_PUT_IN_BUFFER(sas_hw_at_no_check(uppercase+code - 1), chr);
+ }
+ }
+ if ( code == 76 )
+ {
+ PUT_IN_BUFFER(code, 0xf0 );
+ }
+ /* translate for pseudo scan codes */
+ chr = ( sas_hw_at_no_check(kb_flag_3) & LC_E0 ) ? MC_E0 : 0;
+ CHECK_AND_PUT_IN_BUFFER(sas_hw_at_no_check(lowercase+code - 1), chr);
+
+} /* end of keyboard_int() AT version */
+
+
+void kb_idle_poll()
+{
+ /*
+ * this routine is called from bios assembler routines to
+ * cause an idle poll to occur.
+ */
+ IDLE_poll();
+}
+
+
+#ifdef NTVDM
+ /*
+ * Ntvdm has a 16-bit int 16 handler
+ * it requires a few services for idle
+ * detection from softpc...
+ *
+ */
+void keyboard_io()
+{
+ switch (getAH()) {
+ /*
+ * The 16 bit thread has not reached idle status yet
+ * but it is polling the kbd, so do some brief waits.
+ */
+ case 0:
+ WaitIfIdle();
+#ifndef NTVDM
+ if (!WaitKbdHdw(0)) {
+ TryKbdInt();
+ HostReleaseKbd();
+ }
+#endif /* NTVDM */
+ break;
+
+ /*
+ * App wants to idle, so consult idle algorithm
+ */
+ case 1:
+ IDLE_poll();
+ break;
+
+ /*
+ * App is starting a waitio
+ */
+ case 2:
+ IDLE_waitio();
+ break;
+
+ /*
+ * update the keyboard lights,
+ */
+ case 3:
+ host_kb_light_on (getAL());
+ break;
+ }
+}
+
+#else
+void keyboard_io()
+{
+ /*
+ * Request to keyboard. The AH register holds the type of request:
+ *
+ * AH == 0 Read an character from the queue - wait if no
+ * character available. Return character in AL
+ * and the scan code in AH.
+ *
+ * AH == 1 Determine if there is a character in the queue.
+ * Set ZF = 0 if there is a character and return
+ * it in AX (but leave it in the queue).
+ *
+ * AH == 2 Return shift state in AL.
+ *
+ * For AH = 0 to 2, the value returned in AH is zero. This correction
+ * made in r2.69.
+ *
+ * NB : The order of reference/increment of buffer_head is critical to
+ * ensure we do not upset put_in_buffer().
+ *
+ *
+ * XT-SFD BIOS Extended functions:
+ *
+ * AH == 5 Place ASCII char/scan code pair (CL / CH)
+ * into tail of keyboard buffer. Return 0 in
+ * AL if successful, 1 if buffer already full.
+ *
+ * AH == 0x10 Extended read for enhanced keyboard.
+ *
+ * AH == 0x11 Extended function 1 for enhanced keyboard.
+ *
+ * AH == 0x12 Extended shift status. AL contains kb_flag,
+ * AH has bits for left/right Alt and Ctrl keys
+ * from kb_flag_1 and kb_flag_3.
+ */
+ word buffer_head, /* local copy of BIOS data area variable*/
+ buffer_tail, /* local copy of BIOS data area variable*/
+ buffer_ptr; /* pointer into BIOS keyboard buffer */
+
+#define INT16H_DEC 0x12 /* AH decremented by this if invalid command */
+
+ word CS_save, /* CS before recursive CPU call */
+ IP_save; /* IP before recursive CPU call */
+ half_word data, /* byte conyaining typamatic data */
+ status1, /* temp variables used for storing */
+ status2; /* status in funtion 0x12 */
+
+ INT func_index; /* func_index == AH */
+
+
+ setZF(0);
+ func_index = (INT)getAH();
+
+ note_trace1( BIOS_KB_VERBOSE, "Keyboard BIOS func 0x%x", func_index);
+
+
+ switch (func_index) {
+
+ case 0x00: /* Read next char in Kbd buffer */
+
+ /*
+ * The AT emulation of the BIOS uses a recursive CPU to handle
+ * the HW interrrupts, so there is no need to set the Zero Flag
+ * and return to our CPU (see original xt version )
+ */
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ if (buffer_tail == buffer_head)
+ {
+ IDLE_waitio();
+
+ setAX(0x9002);
+ INT15(); /* call int 15h - wait function */
+ }
+
+ do
+ {
+ check_indicators(0); /* see if LED's need updating */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ if (buffer_tail == buffer_head)
+ {
+ CS_save = getCS();
+ IP_save = getIP();
+
+ /* wait for character in buffer */
+
+ do {
+ IDLE_poll();
+
+ setCS(rcpu_poll_segment);
+ setIP(rcpu_poll_offset);
+ host_simulate();
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ } while (buffer_tail == buffer_head);
+
+
+ setCS(CS_save);
+ setIP(IP_save);
+ }
+
+ setAX(sas_w_at_no_check(BIOS_VAR_START + buffer_head));
+
+ buffer_head = inc_buffer_ptr(/* from: */buffer_head);
+ sas_storew_no_check(BIOS_KB_BUFFER_HEAD, buffer_head);
+
+ translate_std(); /*translate scan_code pairs */
+ }
+ while (getCF()); /* if CF set throw code away and start again */
+
+ setIF(1);
+
+ IDLE_init();
+
+ break;
+
+
+ case 0x01: /* Set ZF to reflect char availability in Kbd buffer */
+
+ do
+ {
+ check_indicators(1); /* see if LED's need updating */
+ /* and issue an out 20h,20h */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ setAX(sas_w_at_no_check(BIOS_VAR_START + buffer_head));
+
+ if (buffer_tail == buffer_head)
+ {
+ /* buffer empty - set flag and return */
+ IDLE_poll();
+
+ setZF(1);
+ break;
+ }
+ else
+ IDLE_init();
+
+ translate_std(); /* translate scan_code pairs, returns CF if throwaway */
+ if(getCF())
+ {
+ /* throw code away by incrementing pointer */
+ buffer_head = inc_buffer_ptr(/* from: */buffer_head);
+ sas_storew_no_check(BIOS_KB_BUFFER_HEAD, buffer_head);
+ }
+ }
+ while (getCF()); /* if CF set - start again */
+ setIF(1);
+
+ break;
+
+
+ case 0x02: /* AL := Current Shift Status (really "kb_flag") */
+
+ setAH(0);
+ setAL(sas_hw_at_no_check(kb_flag));
+
+ break;
+
+
+ case 0x03: /* Alter typematic rate */
+
+ /* check for correct values in registers */
+ if( (getAL() == 5) && !(getBX() & 0xfce0) )
+ {
+ note_trace1(BIOS_KB_VERBOSE, "\talter typematic rate (BX %#x)\n", getBX());
+
+ send_data(KB_TYPA_RD);
+ data = (getBH() << 5) | getBL();
+ send_data(data);
+ }
+
+ break;
+
+
+ case 0x05: /* Place ASCII + ScanCode in Kbd Buffer */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ /*
+ * check for sufficient space - if no set AL
+ */
+
+ buffer_ptr = inc_buffer_ptr(/*from:*/buffer_tail);
+
+ if( buffer_head == buffer_ptr )
+ setAL( 1 );
+ else {
+ /*
+ * load CX into buffer and update buffer_tail
+ */
+ sas_storew_no_check(BIOS_VAR_START + buffer_tail, getCX() );
+ sas_storew_no_check(BIOS_KB_BUFFER_TAIL, buffer_ptr);
+ setAL( 0 );
+ }
+ setAH( 0 );
+ setIF(1);
+
+ break;
+
+
+ case 0x10: /* Extended ASCII Read */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ if (buffer_tail == buffer_head)
+ {
+ IDLE_waitio();
+
+ setAX(0x9002);
+ INT15(); /* call int 15h - wait function */
+ }
+ check_indicators(0); /* see if LED's need updating */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ if (buffer_tail == buffer_head)
+ {
+ CS_save = getCS();
+ IP_save = getIP();
+
+ /* wait for character in buffer */
+ while (buffer_tail == buffer_head)
+ {
+ IDLE_poll();
+
+ setCS(rcpu_poll_segment);
+ setIP(rcpu_poll_offset);
+ host_simulate();
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+ }
+
+ IDLE_init();
+
+ setCS(CS_save);
+ setIP(IP_save);
+ }
+
+ setAX(sas_w_at_no_check(BIOS_VAR_START + buffer_head)); /* Pickup the "current" scancode/char pair */
+
+ buffer_head = inc_buffer_ptr(/* from: */buffer_head);
+ sas_storew_no_check(BIOS_KB_BUFFER_HEAD, buffer_head);
+
+ translate_ext(); /* translate scan_code pairs */
+
+ setIF(1);
+ break;
+
+
+ case 0x11: /* Extended ASCII Status */
+
+ check_indicators(1); /* see if LED's need updating */
+ /* and issue an out 20h,20h */
+
+ buffer_head = sas_w_at_no_check(BIOS_KB_BUFFER_HEAD);
+ buffer_tail = sas_w_at_no_check(BIOS_KB_BUFFER_TAIL);
+
+ setAX(sas_w_at_no_check(BIOS_VAR_START + buffer_head));
+
+ if (buffer_tail == buffer_head) /* No keys pressed */
+ {
+ setZF(1);
+ IDLE_poll();
+ }
+ else /* Keystrokes available! */
+ {
+ translate_ext(); /* translate scan_code pairs */
+ IDLE_init();
+ }
+
+ setIF(1);
+ break;
+
+
+ case 0x12: /* Extended Shift Status */
+
+ status1 = sas_hw_at_no_check(kb_flag_1) & SYS_SHIFT; /* only leave SYS KEY */
+ status1 <<= 5; /* move to bit 7 */
+ status2 = sas_hw_at_no_check(kb_flag_1) & 0x73; /* remove SYS_SHIFT, HOLD,
+ STATE and INS_SHIFT */
+ status1 |= status2; /* merge */
+ status2 = sas_hw_at_no_check(kb_flag_3) & 0x0C; /* remove LC_E0 & LC_E1 */
+ status1 |= status2; /* merge */
+ setAH( status1 );
+ setAL( sas_hw_at_no_check(kb_flag) );
+
+ break;
+
+
+ default:
+ setAH((func_index - INT16H_DEC));
+ break;
+ }
+}
+#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
+
+void keyboard_post()
+{
+
+ /* Set up BIOS keyboard variables */
+
+/* Initialize the keyboard table pointers */
+ shift_keys = K6;
+ shift_masks = K7;
+ ctl_n_table = K8;
+ ctl_f_table = K9;
+ lowercase = K10;
+ uppercase = K11;
+ alt_table = K30;
+
+ sas_storew_no_check(BIOS_KB_BUFFER_HEAD, BIOS_KB_BUFFER);
+ sas_storew_no_check(BIOS_KB_BUFFER_TAIL, BIOS_KB_BUFFER);
+ sas_storew_no_check(BIOS_KB_BUFFER_START, BIOS_KB_BUFFER);
+ sas_storew_no_check(BIOS_KB_BUFFER_END, BIOS_KB_BUFFER + 2*BIOS_KB_BUFFER_SIZE);
+
+ /* The following are #defines, referring to locations in BIOS */
+ /* data area. */
+
+ sas_store_no_check (kb_flag,NUM_STATE);
+ sas_store_no_check (kb_flag_1,0);
+ sas_store_no_check (kb_flag_2,2);
+ sas_store_no_check (kb_flag_3,KBX);
+ sas_store_no_check (alt_input,0);
+}
+
+void keyboard_init()
+{
+ /*
+ ** host specific keyboard initialisation
+ ** is now before AT base keyboard initialisation
+ */
+ host_kb_init();
+
+#if defined(CPU_40_STYLE) && !defined (NTVDM)
+ ica_iret_hook_control(ICA_MASTER, CPU_KB_INT, TRUE);
+#endif
+}
+
+
+
+#ifdef NTVDM
+
+/*:::::::::::::::::::::::::::::::::::::::::::::::: Map in new keyboard tables */
+/*::::::::::::::::::::::::::::::::::::::::::::::::::::: Set interrupt vectors */
+/*
+** The Microsoft NTIO.SYS calls this func via BOP 5F to pass
+** interesting addresses to our C BIOS.
+*/
+
+#if defined(MONITOR)
+
+IMPORT UTINY getNtScreenState IPT0();
+#endif
+
+
+void kb_setup_vectors(void)
+{
+ word KbdSeg, w;
+ word *pkio_table;
+ double_word phy_base;
+
+
+ KbdSeg = getDS();
+ pkio_table = (word *) effective_addr(getCS(), getSI());
+
+ /* IDLE variables */
+ sas_loadw((sys_addr)(pkio_table + 12), &w);
+ pICounter = (word *) (Start_of_M_area + ((KbdSeg<<4)+w));
+ pCharPollsPerTick = (word *) (Start_of_M_area + ((KbdSeg<<4)+w+4));
+ pMinConsecutiveTicks = (word *) (Start_of_M_area + ((KbdSeg<<4)+w+8));
+
+#if defined(MONITOR)
+ phy_base = (double_word)KbdSeg << 4;
+
+ /* key tables */
+ shift_keys = phy_base + *pkio_table++;
+ shift_masks = phy_base + *pkio_table++;
+ ctl_n_table = phy_base + *pkio_table++;
+ ctl_f_table = phy_base + *pkio_table++;
+ lowercase = phy_base + *pkio_table++;
+ uppercase = phy_base + *pkio_table++;
+ alt_table = phy_base + *pkio_table++;
+
+ dummy_int_seg = KbdSeg; /* dummy int, iret routine */
+ dummy_int_off = *pkio_table++;
+ int05_seg = KbdSeg; /* print screen caller */
+ int05_off = *pkio_table++;
+ int15_seg = KbdSeg; /* int 15 caller */
+ int15_off = *pkio_table++;
+ rcpu_nop_segment = KbdSeg; /* cpu nop */
+ rcpu_nop_offset = *pkio_table++;
+ sp_int15_handler_seg = KbdSeg; /* int 15 handler */
+ sp_int15_handler_off = *pkio_table++;
+ pkio_table++; /* iDle variables, done above */
+ rcpu_int4A_seg = KbdSeg;
+ rcpu_int4A_off = *pkio_table++; /* real time clock */
+
+ int1b_seg = KbdSeg; /* kbd break handler */
+ int1b_off = *pkio_table++;
+ int10_seg = KbdSeg;
+ int10_caller = *pkio_table++;
+ int10_vector = *pkio_table++;
+
+ /*
+ ** Address of data in keyboard.sys, Tim August 92.
+ **
+ ** useHostInt10 is a one byte variable. 1 means use host video BIOS,
+ ** (ie. full-screen), 0 means use SoftPC video BIOS (ie. windowed).
+ ** babyModeTable is a mini version of the table in ROM that contains
+ ** all the VGA register values for all the modes. The keyboard.sys
+ ** version only has two entries; for 40 column text mode and 80
+ ** column text mode.
+ */
+ useHostInt10 = *pkio_table++;
+ sas_store_no_check((sys_addr)(phy_base + useHostInt10), getNtScreenState());
+ babyModeTable = (int10_seg << 4) + *pkio_table++;
+ changing_mode_flag = *pkio_table++; /* indicates trying to change vid mode*/
+
+ /* Initialise printer status table. */
+ printer_setup_table(effective_addr(KbdSeg, *pkio_table++));
+ wait_int_off = *pkio_table++;
+ wait_int_seg = KbdSeg;
+ dr_type_seg = KbdSeg;
+ dr_type_off = *pkio_table++;
+ dr_type_addr = (sys_addr)dr_type_seg * 16L + (sys_addr)dr_type_off;
+ vga1b_seg = KbdSeg;
+ vga1b_off = *pkio_table++; /* VGA capability table (normally lives in ROM) */
+ conf_15_seg = KbdSeg;
+ conf_15_off = *pkio_table++; /* INT15 config table (normally in ROM) */
+
+ TimerInt08Seg = KbdSeg;
+ TimerInt08Off = *pkio_table++;
+ int13h_vector_seg = KbdSeg;
+ int13h_caller_seg = KbdSeg;
+ int13h_vector_off = *pkio_table++;
+ int13h_caller_off = *pkio_table++;
+ stream_io_buffer_size = *pkio_table++;
+ stream_io_buffer = (half_word *)effective_addr(*pkio_table++, 0);
+ stream_io_dirty_count_ptr = (word *)effective_addr(KbdSeg, *pkio_table++);
+ stream_io_bios_busy_sysaddr = effective_addr(KbdSeg, *pkio_table++);
+#ifndef PROD
+ if (*pkio_table != getAX()) {
+ always_trace0("ERROR: KbdVectorTable!");
+ }
+#endif
+ TimerInt1CSeg = KbdSeg;
+ TimerInt1COff = dummy_int_off;
+
+#else /* ndef MONITOR */
+
+ /* kbd bios callout optimization */
+ sas_loadw(0x15*4, &sp_int15_handler_off);
+ sas_loadw(0x15*4 + 2, &sp_int15_handler_seg);
+
+ /* timer hardware interrupt optimizations */
+ sas_loadw(0x08*4, &TimerInt08Off);
+ sas_loadw(0x08*4 + 2, &TimerInt08Seg);
+ sas_loadw(0x1C*4, &TimerInt1COff);
+ sas_loadw(0x1C*4 + 2, &TimerInt1CSeg);
+
+ sas_loadw(0x13 * 4, &int13h_vector_off);
+ sas_loadw(0x13 * 4 + 2, &int13h_vector_seg);
+ int13h_caller_seg = KbdSeg;
+ dr_type_seg = KbdSeg;
+ sas_loadw((sys_addr)(pkio_table + 27), &int13h_caller_off);
+ sas_loadw((sys_addr)(pkio_table + 22), &dr_type_off);
+ dr_type_addr = effective_addr(dr_type_seg, dr_type_off);
+
+#endif /* MONITOR */
+
+ sas_loadw(0x09*4, &KbdInt09Off);
+ sas_loadw(0x09*4 + 2, &KbdInt09Seg);
+
+ ResumeTimerThread();
+}
+
+
+/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Int15 caller */
+
+
+/*
+ * Gives chance for other parts of NTVDM to
+ * update the kbd i15 kbd callout optimization
+ */
+void UpdateKbdInt15(word Seg,word Off)
+{
+ word int15Off, int15Seg;
+
+ /* make sure nobody has hooked since the last time */
+ /* we stored the i15 vector */
+ sas_loadw(0x15*4 , &int15Off);
+ sas_loadw(0x15*4 + 2, &int15Seg);
+ if(int15Off != sp_int15_handler_off || int15Seg != sp_int15_handler_seg)
+ {
+#ifndef PROD
+ printf("NTVDM: UpdateKbdInt15 Nuking I15 offsets\n");
+#endif
+ sp_int15_handler_off = sp_int15_handler_seg = 0;
+ return;
+ }
+
+ sp_int15_handler_off = Off;
+ sp_int15_handler_seg = Seg;
+}
+
+
+
+IMPORT void (*BIOS[])();
+
+void INT15(void)
+{
+ ULONG ul;
+ word CS_save, IP_save;
+ word int15Off, int15Seg;
+
+ /*:::::::::::::::::::::::::::::::::: Get location of current 15h handler */
+ sas_loadw(0x15*4 , &int15Off);
+ sas_loadw(0x15*4 + 2, &int15Seg);
+
+ /*:::::::::::::::::::::: Does the 15h vector point to the softpc handler */
+ ul = (ULONG)getAH();
+ if((ul == 0x4f || ul == 0x91) &&
+ int15Off == sp_int15_handler_off &&
+ int15Seg == sp_int15_handler_seg)
+ {
+ (BIOS[0x15])(); /* Call int15 handler defined in base */
+ }
+ else
+ {
+ /*::::::::::::::::::::::::::::::::::::::::::::::: Call int15 handler */
+ ul = (ULONG)bBiosOwnsKbdHdw;
+ if (bBiosOwnsKbdHdw) {
+ bBiosOwnsKbdHdw = FALSE;
+ HostReleaseKbd();
+ }
+ CS_save = getCS(); /* Save current CS,IP settings */
+ IP_save = getIP();
+ setCS(int15_seg);
+ setIP(int15_off);
+ host_simulate(); /* Call int15 handler */
+ setCS(CS_save); /* Restore CS,IP */
+ setIP(IP_save);
+ if (ul)
+ bBiosOwnsKbdHdw = !WaitKbdHdw(5000);
+ }
+}
+
+
+/*
+ * 32 bit services for kb16.com, the international 16 bit
+ * interrupt 9 service handler.
+ *
+ */
+void Keyb16Request(half_word BopFnCode)
+{
+
+ /*
+ * upon entry to kb16, take ownership of kbd
+ * disable the kbd
+ * disable interrupts
+ */
+ if (BopFnCode == 1) {
+ bBiosOwnsKbdHdw = !WaitKbdHdw(5000);
+ outb(KEYBA_STATUS_CMD, DIS_KBD);
+ setIF(1);
+ }
+
+ /* K26A type exit from i9 handler */
+ else if (BopFnCode == 2) {
+ if (getBH()) { /* bl == do beep */
+ host_alarm(250000L);
+ }
+
+ outb(0x20, 0x20); /* eoi */
+
+ if (getBL()) { /* got character ? do device post */
+ setAX(0x9102);
+ INT15();
+ }
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ if (bBiosOwnsKbdHdw) {
+ bBiosOwnsKbdHdw = FALSE;
+ HostReleaseKbd();
+ }
+ }
+
+ /* K27A exit notify */
+ else if (BopFnCode == 3) {
+ outb(0x20, 0x20);
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ if (bBiosOwnsKbdHdw) {
+ bBiosOwnsKbdHdw = FALSE;
+ HostReleaseKbd();
+ }
+ }
+
+ /* K27A exit notify */
+ else if (BopFnCode == 4) {
+ outb(KEYBA_STATUS_CMD, ENA_KBD);
+ if (bBiosOwnsKbdHdw) {
+ bBiosOwnsKbdHdw = FALSE;
+ HostReleaseKbd();
+ }
+ }
+}
+
+#endif /* NTVDM */