diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/softpc.new/base/keymouse/keybd_io.c | |
download | NT4.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.c | 2162 |
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 */ |