summaryrefslogblamecommitdiffstats
path: root/private/mvdm/v86/scaffold/i386/fakekbd.c
blob: 8e807548ee68dd4ac2d3ebc394b049fcde4794fb (plain) (tree)
























































































































































































































































































                                                                           

//
// 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);
}