diff options
Diffstat (limited to 'private/mvdm/v86/scaffold/i386/fakekbd.c')
-rw-r--r-- | private/mvdm/v86/scaffold/i386/fakekbd.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/private/mvdm/v86/scaffold/i386/fakekbd.c b/private/mvdm/v86/scaffold/i386/fakekbd.c new file mode 100644 index 000000000..8e807548e --- /dev/null +++ b/private/mvdm/v86/scaffold/i386/fakekbd.c @@ -0,0 +1,281 @@ + +// +// Fake Keyboard rom support +// +// This file provides interrim support for keyboard rom bios services. +// It is only intended for use until Insignia produces proper rom support +// for NTVDM +// +// Note: portions of this code were lifted from the following source. + +/* x86 v1.0 + * + * XBIOSKBD.C + * Guest ROM BIOS keyboard emulation + * + * History + * Created 20-Oct-90 by Jeff Parsons + * + * COPYRIGHT NOTICE + * This source file may not be distributed, modified or incorporated into + * another product without prior approval from the author, Jeff Parsons. + * This file may be copied to designated servers and machines authorized to + * access those servers, but that does not imply any form of approval. + */ + +#include <windows.h> +#include <stdio.h> +#include <conio.h> +#include <string.h> +#include "softpc.h" +#include "bop.h" +#include "xbios.h" +#include "xbioskbd.h" +#include "xwincon.h" +#include "fun.h" +#include <conapi.h> + +extern HANDLE InputHandle; + +#define MAX_KBD_BUFFER 256 +CHAR KbdBuffer[MAX_KBD_BUFFER]; +ULONG Head=0,Tail=0; +HANDLE KbdSyncEvent; +CRITICAL_SECTION csKbd; +CRITICAL_SECTION csConsole; +CRITICAL_SECTION csCtrlc; +BOOL fEventThreadBlock = FALSE; +HANDLE hConsoleWait; +ULONG nCtrlc=0; + +HANDLE StdIn; + +static BYTE ServiceRoutine[] = { 0xC4, 0xC4, BOP_KBD, 0x50, 0x55, 0x8B, + 0xEC, 0x9C, 0x58, 0x89, 0x46, 0x08, 0x5d, 0x58, 0xCF }; +#define SERVICE_LENGTH sizeof(ServiceRoutine) + +/* BiosKbdInit - Initialize ROM BIOS keyboard support + * + * ENTRY + * argc - # of command-line options + * argv - pointer to first option pointer + * ServiceAddress - linear address to put service routine at + * + * EXIT + * TRUE if successful, FALSE if not + */ + +BOOL BiosKbdInit(int argc, char *argv[], PVOID *ServiceAddress) +{ + PVOID Address; + + argc, argv; + + memcpy(*ServiceAddress, ServiceRoutine, SERVICE_LENGTH); + + Address = (PVOID)(BIOSINT_KBD * 4); + *((PWORD)Address) = RMOFF(*ServiceAddress); + *(((PWORD)Address) + 1) = RMSEG(*ServiceAddress); + (PCHAR)*ServiceAddress += SERVICE_LENGTH; + + StdIn = GetStdHandle(STD_INPUT_HANDLE); + + KbdSyncEvent = CreateEvent( NULL, TRUE, FALSE,NULL ); + + InitializeCriticalSection (&csKbd); + InitializeCriticalSection(&csConsole); + InitializeCriticalSection(&csCtrlc); + + hConsoleWait = CreateEvent (NULL,TRUE,FALSE,NULL); + + return TRUE; +} + + +/* BiosKbd - Emulate ROM BIOS keyboard functions + * + * ENTRY + * None (x86 registers contain parameters) + * + * EXIT + * None (x86 registers/memory updated appropriately) + * + * This function receives control on INT 16h, routes control to the + * appropriate subfunction based on the function # in AH, and + * then simulates an IRET and returns back to the instruction emulator. + */ + +VOID BiosKbdReadLoop (VOID) +{ +ULONG Temp; + + while (1) { + + Temp = Head + 1; + if(Temp >= MAX_KBD_BUFFER) + Temp =0; + if(Temp == Tail){ + Sleep (20); + continue; + } + + KbdBuffer[Head] = getche(); + + EnterCriticalSection(&csConsole); + if(fEventThreadBlock == TRUE){ + LeaveCriticalSection(&csConsole); + WaitForSingleObject(hConsoleWait,-1); + ResetEvent(hConsoleWait); + continue; + } + else{ + LeaveCriticalSection(&csConsole); + } + + EnterCriticalSection(&csKbd); + Head = Temp; + LeaveCriticalSection(&csKbd); + SetEvent(KbdSyncEvent); + } +} + +BOOL tkbhit(VOID) +{ + + if (Tail != Head || nCtrlc) + return TRUE; + return FALSE; +} + + +CHAR tgetch(VOID) +{ +CHAR ch; + + while(TRUE) { + EnterCriticalSection(&csCtrlc); + if (nCtrlc){ + nCtrlc--; + LeaveCriticalSection(&csCtrlc); + return (CHAR)0x3; // return ctrlc + } + LeaveCriticalSection(&csCtrlc); + + if (Tail != Head) { + EnterCriticalSection(&csKbd); + ch = KbdBuffer[Tail++]; + if (Tail >= MAX_KBD_BUFFER) + Tail = 0; + LeaveCriticalSection(&csKbd); + return ch; + } + WaitForSingleObject(KbdSyncEvent, -1); + ResetEvent(KbdSyncEvent); + } +} + + + + +VOID BiosKbd() +{ + static ULONG ulch; + DWORD nRead=0; + + switch(getAH()) { + + case KBDFUNC_READCHAR: + if (ulch) { + setAL(ulch & 0xff); + setAH(ulch & 0xFF00); + ulch = 0; + } + else { + setAH(0); // zero scan code field for now + setAL((BYTE)tgetch()); + if (getAL() == 0 || getAL() == 0xE0) { + setAL(0); + setAH((BYTE)tgetch()); + } + } + break; + + case KBDFUNC_PEEKCHAR: + setZF(1); + if (ulch) { + setAL(ulch & 0xFF); + setAH(ulch & 0xFF00); + setZF(0); + } + else if(tkbhit()) { + setAH(0); // zero scan code field for now + setAL((BYTE)tgetch()); + if (getAL() == 0 || getAL() == 0xE0) { + setAL(0); + setAH((BYTE)tgetch()); + } + ulch = getAL() | getAH()<<8 | 0x10000; + setZF(0); + } + break; + } +} + + +void nt_block_event_thread(void) +{ + INPUT_RECORD InputRecord; + DWORD nRecordsWritten; + + InputRecord.EventType = 1; + InputRecord.Event.KeyEvent.bKeyDown = 1; + InputRecord.Event.KeyEvent.wRepeatCount = 1; + InputRecord.Event.KeyEvent.wVirtualKeyCode = 32; + InputRecord.Event.KeyEvent.wVirtualScanCode = 41; + InputRecord.Event.KeyEvent.uChar.AsciiChar = ' '; + InputRecord.Event.KeyEvent.dwControlKeyState = 32; + EnterCriticalSection(&csConsole); + WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten); + InputRecord.EventType = 1; + InputRecord.Event.KeyEvent.bKeyDown = 0; + InputRecord.Event.KeyEvent.wRepeatCount = 1; + InputRecord.Event.KeyEvent.wVirtualKeyCode = 32; + InputRecord.Event.KeyEvent.wVirtualScanCode = 41; + InputRecord.Event.KeyEvent.uChar.AsciiChar = ' '; + InputRecord.Event.KeyEvent.dwControlKeyState = 32; + WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten); + fEventThreadBlock = TRUE; + LeaveCriticalSection(&csConsole); + return; + +} + +void nt_resume_event_thread(void) +{ + fEventThreadBlock = FALSE; + SetEvent (hConsoleWait); + return; +} + +// TEMP Till we have proper multitasking in WOW +extern BOOL VDMForWOW; +extern ULONG iWOWTaskId; + + +VOID VDMCtrlCHandler(ULONG ulCtrlType) +{ +// DebugBreak(); + if(ulCtrlType == SYSTEM_ROOT_CONSOLE_EVENT) { + if(VDMForWOW) + // Kill everything for WOW VDM + ExitVDM(VDMForWOW,(ULONG)-1); + else + ExitVDM(FALSE,0); + ExitProcess(0); + return; + } + EnterCriticalSection(&csCtrlc); + nCtrlc++; + LeaveCriticalSection(&csCtrlc); + SetEvent(KbdSyncEvent); +} |