282 lines
6.3 KiB
C
282 lines
6.3 KiB
C
|
|
||
|
//
|
||
|
// 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);
|
||
|
}
|