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/host/src | |
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/host/src')
59 files changed, 47707 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/host/src/config.c b/private/mvdm/softpc.new/host/src/config.c new file mode 100644 index 000000000..1115980b6 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/config.c @@ -0,0 +1,1293 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> + +#include "windows.h" +#include "host_def.h" +#include "insignia.h" +/* + * config.c - config for the NT port. + * + * A happy chainsaw production by Ade Brownlow + * + * This file is a hacked down (seriously) version of the 3.0 config. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "vdmapi.h" + +#include "xt.h" +#include "error.h" +#include "config.h" +#include "sas.h" + +#include "spcfile.h" +#include "umb.h" + +#include "nt_pif.h" /* PIF file interrogation data structure types */ +#include "trace.h" + +#include "conapi.h" +#include "nt_graph.h" +#include "gfi.h" +#include "floppy.h" + +#include "ntddvdeo.h" +#include "host_rrr.h" +#include "nt_fulsc.h" +#include "nt_uis.h" +#include "nt_event.h" +#include "nt_reset.h" +#include "nt_fdisk.h" + +#ifdef LIM +#include "emm.h" +#endif + +#include "oemuni.h" + +#include "pmvdm.h" + +#ifdef HUNTER + +#include "ckmalloc.h" +#include "debug.h" +#endif //HUNTER + + +/*================================================================ +External references +================================================================*/ +IMPORT SHORT gfi_floppy_active (UTINY hostID, BOOL active, CHAR *err); +IMPORT ULONG xmsMemorySize; + +#ifdef HUNTER +/* + * =========================================================================== + * LOCAL DATA STRUCTURES + * =========================================================================== + */ + +typedef struct { + ConfigValues *data; + OptionDescription *def; +} ConfTabEntry; + +/* + * =========================================================================== + * LOCAL FUNCTIONS + * =========================================================================== + */ +VOID build_data_table(VOID); +VOID read_trapper_variables(VOID); +VOID convert_arg(CHAR *, OptionDescription *, ConfigValues *); +SHORT check_value(OptionDescription *, ConfigValues *); + +/* + * =========================================================================== + * IMPORTED DATA STRUCTURES + * =========================================================================== + */ + +IMPORT OptionDescription host_defs[]; /* From hunt_conf.c */ + +/* + * =========================================================================== + * LOCAL DATA + * =========================================================================== + */ + +/* Dummy `common_defs' to pass to `host_config_init' */ +LOCAL OptionDescription common_defs[] = +{ + { NULL, NULL, NULL, NULL, NULL, -1, C_RECORD_DELETE } +}; +LOCAL ConfTabEntry *conf_tab = NULL; + +#endif /* HUNTER */ + + +PIF_DATA pfdata; /* data structure for holding all the relavent information + from the PIF file interrogated */ +/* must be unsigned because they can be over 32768 */ +USHORT PIFExtendMemSize = 0; /* save value of extend mem from PIF file */ +USHORT PIFEMSMemSize = 0; /* save value of LIM mem from PIF file */ +ULONG emsMemorySize; + +#ifdef LIM +LIM_CONFIG_DATA lim_config_data = {FALSE, 0, 0, 640 * 1024 / 16, FALSE}; +#endif + +APPKEY Shortkey; /* PIF Shortcut key settings */ +BYTE ReserveKey; /* PIF Reserved key setting */ +int nShortKeys; +/* + * =========================================================================== + * GLOBAL DATA + * =========================================================================== + */ +GLOBAL SHORT Npx_enabled = TRUE; //For Jazz CPU support +GLOBAL BOOL IdleDisabledFromPIF = FALSE;//Flag showing idledetection wishes +GLOBAL UTINY number_of_floppy = 0; // number of floppy drives + + +/*================================================================ +Local defines +================================================================*/ +/* command definitions for read_profile_int */ + +#define PROFILE_LPT_AUTOCLOSE_DELAY 0 +#define PROFILE_COM_AUTOCLOSE_DELAY 1 +#define PROFILE_LPT_AUTOFLUSH_DELAY 2 +#define PROFILE_COM_SYNCWRITE 3 +#define PROFILE_COM_TXBUFFER_SIZE 4 +#define PROFILE_MAX_INDEX PROFILE_COM_TXBUFFER_SIZE + 1 + +#define EMBITSET 0x4 + +#define ONEMEG 0x100000L +#define ONEKB 0x400L + +#define RESERVED_LENGTH 129 +#define PMVDM_NTVDM_NAME "ntvdm." +#define PMVDM_NTVDM_NAME_LENGTH 6 /* doesn't include NULL */ + +#define XMS_DEFAULT_MEMORY_SIZE 15*1024 +#define EMS_DEFAULT_MEMORY_SIZE 4*1024 +#define DPMI_DEFAULT_MEMORY_SIZE_FOR_DOS 8*1024 +#define DPMI_DEFAULT_MEMORY_SIZE_FOR_WOW 16*1024 +/* maximum ems memory size */ +#define EMS_MAX_MEMORY_SIZE 32 * 1024 /* from EMM 4.0 specification */ + +int read_profile_int(int index); +ULONG GetVDMSize(BOOL); +ULONG GetDefaultVDMSize(BOOL); +void InitNtCpuInfo(void); + +/* + * =========================================================================== + * GLOBAL FUNCTIONS + * =========================================================================== + */ + +VOID host_fdisk_active(UTINY hostID, BOOL active, CHAR *errString); +VOID host_fdisk_valid + (UTINY hostID, ConfigValues *vals, NameTable *table, CHAR *errStr); + +/* This routine is called when the DOS VDM runs its first binary. The + parameter points to full path name of the dos app. This routine does'nt + get called on subsequent dos apps in the same console window. It is not + called on wow apps. + Read PIF file and update VDM and console state from settings. +*/ + +VOID process_pif_exe (char *PifName) +{ +#ifdef X86GFX + COORD scrSize; + DWORD flags; +#endif + + GetPIFData(&pfdata, PifName); + + // get app specific LIM memory size + PIFEMSMemSize = pfdata.emsdes; + + // get app specific Extended memory size + PIFExtendMemSize = pfdata.xmsdes; + + // store pif setting for AllowCloseOnExit + if (pfdata.menuclose == 1) { + CntrlHandlerState |= CNTRL_PIFALLOWCLOSE; + } + + /* set app reserved key only if it has a new console; + set app short cut keys only if it has a new console + and there are not short cut keys come along with CreateProcess + Reserved key must be set before set console display mode + */ + nShortKeys = 0; + ReserveKey = 0; + if (DosSessionId || (pfdata.AppHasPIFFile && pfdata.SubSysId == SUBSYS_DOS)) + { + ReserveKey = pfdata.reskey; + if (!pfdata.IgnoreShortKeyInPIF) { + Shortkey.Modifier = pfdata.ShortMod; + Shortkey.ScanCode = pfdata.ShortScan; + nShortKeys = (Shortkey.Modifier || Shortkey.ScanCode) ? 1 : 0; + } + if (ReserveKey || nShortKeys) + SetConsoleKeyShortcuts(TRUE, + ReserveKey, + (nShortKeys) ? &Shortkey : NULL, + nShortKeys + ); + } + + if (pfdata.idledetect == 1) + IdleDisabledFromPIF = FALSE; + else + IdleDisabledFromPIF = TRUE; +#ifdef X86GFX + if (DosSessionId) /* Only check screen state if we are in a NEW_CONSOLE */ + { + /* Check to see if we are currently running windowed or full-screen. */ + if (!GetConsoleDisplayMode(&flags)) + ErrorExit(); + + /* If PIF is telling us to switch to a different state, do so. */ + if (flags & CONSOLE_FULLSCREEN_HARDWARE) + { + if (pfdata.fullorwin == PF_WINDOWED) + { +#ifndef PROD + fprintf(trace_file, "Going windowed...\n"); +#endif /* PROD */ + if (!SetConsoleDisplayMode(sc.OutputHandle, + CONSOLE_WINDOWED_MODE, + &scrSize)) + ErrorExit(); + } + } + else /* WINDOWED */ + { + if (pfdata.fullorwin == PF_FULLSCREEN) + { +#ifndef PROD + fprintf(trace_file, "Going fullscreen...\n"); +#endif /* PROD */ + if (!SetConsoleDisplayMode(sc.OutputHandle, + CONSOLE_FULLSCREEN_MODE, + &scrSize)) + { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + RcErrorDialogBox(ED_INITFSCREEN, NULL, NULL); + } + else { + ErrorExit(); + } + } + } + } + } +#endif /* X86GFX */ + +} + +/* Turn off the PIF reserved & shortcut keys - on block and quit */ +void DisablePIFKeySetup(void) +{ + /* only doing this if the application was launched from a new console */ + if (ReserveKey || nShortKeys) + SetConsoleKeyShortcuts(TRUE, 0, (APPKEY *)0, 0); +} + +/* Turn on the PIF reserved & shortcut keys - on resume */ +void EnablePIFKeySetup(void) +{ + /* only doing this if the app has a new console.*/ + if (ReserveKey || nShortKeys) + SetConsoleKeyShortcuts(TRUE, + ReserveKey, + (nShortKeys) ? &Shortkey : NULL, + nShortKeys + ); + +} + + +GLOBAL VOID config( VOID ) +{ + VDMINFO GetPIF; + char UniqueTitle[64]; + char Title[MAX_PATH]; + char PifName[MAX_PATH + 1]; + char CurDir[MAX_PATH + 1]; + char Reserved[RESERVED_LENGTH]; + char achRoot[] = "=?:"; + char ch, *pch, *pch1; + UTINY hostID; + int i; + DWORD dw; + char achPIF[] = ".pif"; + ULONG dpmiMemorySize, vdmMemorySize; + +#ifdef HUNTER + + /* Build table in which to store config data. */ + build_data_table(); + + /* Initialise optionName fields of host_defs table. */ + host_config_init(common_defs); + + /* Read in trapper variables from environment. */ + read_trapper_variables(); + +#endif /* HUNTER */ + + /* + * Set the window title to a unique string, to get + * the Consoles Window Handle, we will retrieve + * the window handle later when user server has + * had a chance to think about it. + */ + Title[0] = '\0'; + if (!VDMForWOW) { + if (!DosSessionId && !GetConsoleTitle(Title, MAX_PATH)) + Title[0] = '\0'; + sprintf(UniqueTitle, "ntvdm-%lx.%lx.%lx", + GetCurrentProcessId(), GetCurrentThreadId(), + NtCurrentPeb()->ProcessParameters->ConsoleHandle); + SetConsoleTitle(UniqueTitle); + } + else { + strcpy(Title, "Hidden Console of WOW VDM"); + } + + + /* + * Register with srvvdm + * Get PifName, ExecName + */ + GetPIF.PifFile = PifName; + GetPIF.PifLen = MAX_PATH; + GetPIF.EnviornmentSize = 0; + GetPIF.Enviornment = NULL; + + if (fSeparateWow) { + GetPIF.VDMState = ASKING_FOR_PIF | ASKING_FOR_SEPWOW_BINARY; + } + else if (VDMForWOW) { + GetPIF.VDMState = ASKING_FOR_PIF | ASKING_FOR_WOW_BINARY; + } + else { + GetPIF.VDMState = ASKING_FOR_PIF | ASKING_FOR_DOS_BINARY; + } + + GetPIF.CmdLine = NULL; + GetPIF.CmdSize = 0; + GetPIF.AppName = NULL; + GetPIF.AppLen = 0; + GetPIF.iTask = DosSessionId; + GetPIF.Desktop = NULL; + GetPIF.DesktopLen = 0; + GetPIF.ReservedLen = (VDMForWOW) ? 0 : RESERVED_LENGTH; + GetPIF.Reserved = (VDMForWOW) ? NULL : Reserved; + GetPIF.CurDirectoryLen = MAX_PATH + 1; + GetPIF.CurDirectory = CurDir; + + // ask for title if we don't already have one + if (!*Title) { + GetPIF.Title = Title; + GetPIF.TitleLen = MAX_PATH; + } + else { + GetPIF.Title = NULL; + GetPIF.TitleLen = 0; + } + + PifName[0] = '\0'; + pfdata.IgnoreTitleInPIF = 0; + pfdata.IgnoreStartDirInPIF = 0; + pfdata.IgnoreShortKeyInPIF = 0; + if (GetNextVDMCommand(&GetPIF)) { + /* parsing the reserve field to decide if + we should take StartDir, Title and hotkey from + pif file. See windows\inc\pmvdm.h for the detail + */ + + Reserved[GetPIF.ReservedLen] = '\0'; + if (!VDMForWOW && GetPIF.ReservedLen && + (pch = strstr(Reserved, PMVDM_NTVDM_NAME)) != NULL) + { + pch += PMVDM_NTVDM_NAME_LENGTH; + pch1 = pch; + dw = 0; + while(*pch >= '0' && *pch <= '9') + pch++; + if (pch1 != pch) { + ch = *pch; + *pch = '\0'; + dw = (DWORD) strtol(pch1, (char **)NULL, 10); + *pch = ch; + if (dw & PROPERTY_HAS_CURDIR) + pfdata.IgnoreStartDirInPIF = 1; + if (dw & PROPERTY_HAS_HOTKEY) + pfdata.IgnoreShortKeyInPIF = 1; + if (dw & PROPERTY_HAS_TITLE) + pfdata.IgnoreTitleInPIF = 1; + } + } + if (GetPIF.CurDirectoryLen) { + achRoot[1] = CurDir[0]; + + /* these needs to be ANSI calls not OEM as server passes + the informatio in ANSI*/ + + SetEnvironmentVariable(achRoot, CurDir); + SetCurrentDirectory(CurDir); + + } + } + + + pfdata.IgnoreCmdLineInPIF = 0; + pfdata.IgnoreConfigAutoexec = 0; + pfdata.AppHasPIFFile = PifName[0] ? 1 : 0; + + if(VDMForWOW){ + DosSessionId = 0; // Wow has hidden console ! + pfdata.IgnoreCmdLineInPIF = + pfdata.IgnoreTitleInPIF = + pfdata.IgnoreStartDirInPIF = 1; + pfdata.IgnoreShortKeyInPIF = 1; + } + + process_pif_exe(PifName); + + sas_term (); + + // + // Calculate how big xms and ems will be. + // XMS and EMS memory sizes are either taken from a PIF file, or + // supplied from default values. + // + + if (VDMForWOW) { + + // + // For WOW, we don't need any EMS, and we just need enough + // XMS to satisfy win16 apps looking at the real machine size + // + emsMemorySize = 0; + xmsMemorySize = 8192; + dpmiMemorySize = DPMI_DEFAULT_MEMORY_SIZE_FOR_WOW; + } else { + + emsMemorySize = PIFEMSMemSize == (USHORT)(-1) + ? EMS_DEFAULT_MEMORY_SIZE + : PIFEMSMemSize; + + /* maximum size is 63MB */ + xmsMemorySize = PIFExtendMemSize == (USHORT)(-1) + ? XMS_DEFAULT_MEMORY_SIZE + : PIFExtendMemSize; + + /* put a upper limit on ems memory size based on EMM 4.0 spec */ + if (emsMemorySize > EMS_MAX_MEMORY_SIZE) + emsMemorySize = EMS_MAX_MEMORY_SIZE; + + // Force at least 1 megabyte xms to keep himem and dosx working. + if (xmsMemorySize < 1024) { + xmsMemorySize = 1024; + } + dpmiMemorySize = DPMI_DEFAULT_MEMORY_SIZE_FOR_DOS; + } + +#ifdef LIM + /* !!!! THIS MUST BE DONE BEFORE CALLING SAS_INIT !!!!!! */ + if(!VDMForWOW && config_inquire(C_LIM_SIZE, NULL) && + init_lim_configuration_data(&lim_config_data)) + lim_config_data.initialized = TRUE; + +#endif + + // + // Add everything up to decide how much physically installed memory + // the virtual machine needs. On RISC platforms, we may create a + // larger machine than xms or ems would call for to provide for + // dpmi memory. We get this size from the registry. + // + +#ifdef i386 + // adding 1024 below is for conventional memory + vdmMemorySize = xmsMemorySize + emsMemorySize + 1024; +#else + vdmMemorySize = GetVDMSize(VDMForWOW); + + // Extend the vdm size if the user asks for it through a .PIF. + // Also make sure we have at least appropriate size of dpmi + // memory. + // + if ((xmsMemorySize + emsMemorySize + 1024 + dpmiMemorySize) > + vdmMemorySize) + { + vdmMemorySize = xmsMemorySize + emsMemorySize + 1024 + + dpmiMemorySize; + } +#endif + +#ifndef PROD + dpmiMemorySize = vdmMemorySize - (xmsMemorySize + emsMemorySize + 1024); + + printf("NTVDM: %dK Memory: %dK XMS, %dK EMS, %dK DPMI\n", + vdmMemorySize, xmsMemorySize, emsMemorySize, dpmiMemorySize); +#endif + + sas_init(vdmMemorySize*ONEKB); + + +#ifdef CPU_40_STYLE + + /* sas_init has initialised Gdp, so now we can set up the pointers */ + /* to the Gdp variables that hold register values. This is to */ + /* allow NTSD debugger extensions to display those values. */ + InitNtCpuInfo(); + +#endif + + +#ifdef X86GFX + GetROMsMapped(); /* before anyone else can toy with memory */ + + locateNativeBIOSfonts(); /* get fonts from page 0 */ +#endif + + // Now see if we can get the console window handle + if (!VDMForWOW) { + i = 6; + do { + hWndConsole = FindWindow("ConsoleWindowClass", UniqueTitle); + if (!hWndConsole && i) + Sleep(10); + } while (!hWndConsole && i--); + if (!hWndConsole) { + hWndConsole = HWND_DESKTOP; +#ifndef PROD + printf("NTVDM: using HWND_DESKTOP\n"); +#endif + } + } + + // set the initial console title + if (*Title) + SetConsoleTitle(Title); + + + +// Create UMB list (both MIPS and x86) -- williamh + InitUMBList(); +// + host_runtime_init(); /* initialise the runtime system */ + + + /* Do not attempt to initialise printer system here */ +// activate(open) floppy drives if there are any + number_of_floppy = 0; + for (i = 0, hostID = C_FLOPPY_A_DEVICE; i < MAX_FLOPPY; i++, hostID++) + if ((gfi_floppy_active(hostID, 1, NULL)) == C_CONFIG_OP_OK) + number_of_floppy++; +} + +GLOBAL VOID * +config_inquire(UTINY hostID, ConfigValues *values) +{ + /* Must be a static because returned to called */ + // BUGBUG should be change (caller provides buffer!!!) + static ConfigValues tmp_vals; + + if(!values) values = &tmp_vals; + + /*:::::::::::::::::::::::::::::::::::::: Hardwire the config stuff */ + + switch (hostID) + { + case C_HARD_DISK1_NAME: + // + // this dubious practice will satisfy the disk + // bios to exist quietly enough for initialisation + // after which, DOS emulation should ensure no more + // disk bios calls are made. + // + host_using_fdisk(FALSE); // tell fdisk it's ok to fail + strcpy (values->string, "?"); + return ((VOID *) values->string); + + + case C_HARD_DISK2_NAME: + strcpy (values->string, ""); + { + char tmp[100]; + host_fdisk_valid (hostID, values, NULL, tmp); + host_fdisk_change (hostID, TRUE); + host_fdisk_active (hostID, TRUE, tmp); + } + + return ((VOID *) values->string); + + + case C_GFX_ADAPTER: + values->index = VGA; + return ((VOID *)VGA); + + case C_WIN_SIZE: + values->index = 2; /* 2, 3 or 4. */ + return ((VOID *) values->index); + + case C_EXTENDED_MEM_SIZE: + values->index = (SHORT)(xmsMemorySize/1024); + return ((VOID *)values->index); + + case C_LIM_SIZE: + values->index = (SHORT)(emsMemorySize/1024); + return ((VOID *)values->index); + + case C_MEM_LIMIT: + values->index = 640; + return ((VOID *)values->index); + + case C_COM1_NAME: + strcpy (values->string, "COM1"); + values->index = (short)read_profile_int(PROFILE_COM_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_COM2_NAME: + strcpy (values->string, "COM2"); + values->index = (short)read_profile_int(PROFILE_COM_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_COM3_NAME: + strcpy (values->string, "COM3"); + values->index = (short)read_profile_int(PROFILE_COM_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_COM4_NAME: + strcpy (values->string, "COM4"); + values->index = (short)read_profile_int(PROFILE_COM_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_LPT1_NAME: + strcpy (values->string, "LPT1"); + values->index = (short)read_profile_int(PROFILE_LPT_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_LPT2_NAME: + strcpy (values->string, "LPT2"); + values->index = (short)read_profile_int(PROFILE_LPT_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + case C_LPT3_NAME: + strcpy (values->string, "LPT3"); + values->index = (short)read_profile_int(PROFILE_LPT_AUTOCLOSE_DELAY); + return ((VOID *) values->string); + + +/* Auto flush closes the port after 'n' seconds of inactivaty */ + + case C_AUTOFLUSH: + values->index = TRUE; + return ((VOID *)values->index); + + case C_AUTOFLUSH_DELAY: + values->index = read_profile_int(PROFILE_LPT_AUTOFLUSH_DELAY); //Delay in secs + return((VOID *)values->index); + +//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + + case C_FSA_DIRECTORY: + strcpy (values->string, "\\"); + return ((VOID *) values->string); + + case C_VDMLPT1_NAME: + strcpy(values->string, "\\\\.\\$VDMLPT1"); + return ((VOID *)values->string); + case C_VDMLPT2_NAME: + strcpy(values->string, "\\\\.\\$VDMLPT2"); + return ((VOID *)values->string); + case C_VDMLPT3_NAME: + strcpy(values->string, "\\\\.\\$VDMLPT3"); + return ((VOID *)values->string); + + +#ifdef HUNTER + + case C_HU_FILENAME: + case C_HU_MODE: + case C_HU_BIOS: + case C_HU_REPORT: + case C_HU_SDTYPE: + case C_HU_CHKMODE: + case C_HU_CHATTR: + case C_HU_SETTLNO: + case C_HU_FUDGENO: + case C_HU_DELAY: + case C_HU_GFXERR: + case C_HU_TS: + case C_HU_NUM: + switch (conf_tab[hostID].def->flags & C_TYPE_MASK) + { + case C_STRING_RECORD: + strcpy(values->string, + conf_tab[hostID].data->string); + return ((VOID *) values->string); + case C_NAME_RECORD: + case C_NUMBER_RECORD: + values->index = conf_tab[hostID].data->index; + return ((VOID *) values->index); + default: + break; + } + break; + +#endif /* HUNTER */ + + case C_COM_SYNCWRITE: + values->index = (short)read_profile_int(PROFILE_COM_SYNCWRITE); + return ((VOID *)values->index); + + case C_COM_TXBUFFER_SIZE: + values->index = (short)read_profile_int(PROFILE_COM_TXBUFFER_SIZE); + return ((VOID *)values->index); + + default: /* ie everything else */ + /* fail */ + break; + } + /* setup dummy values to stop loud explosions */ + strcpy (values->string, ""); + + return ((VOID *) values->string); + +} + +GLOBAL VOID config_set_active(UTINY hostID, BOOL state) +{ + UNREFERENCED_FORMAL_PARAMETER(hostID); + UNREFERENCED_FORMAL_PARAMETER(state); + /* do nothing */ +} + +GLOBAL CHAR *convert_to_external(UTINY hostID) +{ + UNREFERENCED_FORMAL_PARAMETER(hostID); + return (NULL); +} + +GLOBAL CHAR * +find_optionname(UTINY hostID) +{ + + UNREFERENCED_FORMAL_PARAMETER(hostID); + return (NULL); +} + +GLOBAL BOOL +config_get_active(UTINY hostID) +{ + + + UNREFERENCED_FORMAL_PARAMETER(hostID); + /* It worked whatever it was supposed to do */ + return (TRUE); +} + +GLOBAL VOID +config_activate(UTINY hostID, BOOL reqState) +{ + + UNREFERENCED_FORMAL_PARAMETER(hostID); + UNREFERENCED_FORMAL_PARAMETER(reqState); + + /* do bugger all */ +} + +GLOBAL char * host_expand_environment_vars IFN1(const char *, string) +{ + + /* we're not going to use the environment for lookups */ + return ((char *)string); +} + +/********************************************************/ +/* host runtime stuff */ +struct +{ + short mouse_attached; + short config_verbose; + short npx_enabled; + short sound_on; +} runtime_status = { + FALSE, FALSE, TRUE, TRUE}; + +void host_runtime_init() +{ +#ifdef MONITOR + CONTEXT txt; + + // get Floating point info for system. + txt.ContextFlags = CONTEXT_FLOATING_POINT; + if (! GetThreadContext(GetCurrentThread(), &txt) ) + { + runtime_status.npx_enabled = FALSE; //dont know for sure so be safe + } + else + { +#if 0 /* if the correct fix ever is made... */ + if (txt.FloatSave.Cr0NpxState & EMBITSET) + runtime_status.npx_enabled = FALSE; //EM only on if no NPX + else + runtime_status.npx_enabled = TRUE; //NPX present. +#endif + + // If no coprocessor, the CONTEXT_F_P bit will have been cleared + if ((txt.ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + runtime_status.npx_enabled = TRUE; //EM only on if no NPX + else + runtime_status.npx_enabled = FALSE; + } +#else + runtime_status.npx_enabled = TRUE; +#endif +} + +short host_runtime_inquire IFN1(UTINY, what) +{ + switch (what) + { + case C_MOUSE_ATTACHED: + return (runtime_status.mouse_attached); + case C_NPX_ENABLED: + return (runtime_status.npx_enabled); + case C_SOUND_ON: + return (runtime_status.sound_on); + default: +#ifndef PROD + fprintf (trace_file,"host_runtime_inquire : Unknown option %d\n",what); +#endif + ; + } +} + +void host_runtime_set IFN2(UTINY, what, SHORT, val) +{ + switch (what) + { + case C_MOUSE_ATTACHED: + runtime_status.mouse_attached = val; + break; + case C_NPX_ENABLED: + runtime_status.npx_enabled = val; + break; + case C_SOUND_ON: + runtime_status.sound_on = val; + break; + default: +#ifndef PROD + fprintf (trace_file,"host_runtime_set : Unknown option %d\n",what); +#endif + ; + } +} + + + +#ifdef HUNTER + +/* + * ========================================================================== + * Function: translate_to_string. + * + * Taken from `conf_util.c' which we don't use. Takes a SHORT and returns + * the corresponding string in the `NameTable'. + * ========================================================================== + */ +GLOBAL CHAR * +translate_to_string(SHORT value, NameTable table[]) +{ + FAST NameTable *nameTabP; + + for (nameTabP = table; nameTabP->string; nameTabP++) + if (nameTabP->value == value) + break; + + return nameTabP->string; +} + +/* + * ========================================================================== + * Function: translate_to_value. + * + * Taken from `conf_util.c' which we don't use. Takes a string and returns + * the corresponding SHORT in the `NameTable'. + * ========================================================================== + */ +GLOBAL SHORT +translate_to_value(CHAR *string, NameTable table[]) +{ + FAST NameTable *nameTabP; + + for (nameTabP = table; nameTabP->string; nameTabP++) + if(!strcmp(string, nameTabP->string)) + break; + + return (!nameTabP->string)? C_CONFIG_NOT_VALID : nameTabP->value; +} + +/* + * ========================================================================== + * Function: validate_item. + * + * Taken from `conf_def.c' which we don't use. Needed because `hunt_conf.c' + * uses it as the validation routine for several `config' variables (see + * `host_defs' table in `hunt_conf.c'). + * ========================================================================== + */ +GLOBAL SHORT +validate_item(UTINY hostID, ConfigValues *value, + NameTable *table, CHAR *err) +{ + char *what; + + if (!(what = translate_to_string(value->index, table))) + { + *err = '\0'; + return EG_BAD_VALUE; + } + return C_CONFIG_OP_OK; +} + +/* + * ========================================================================== + * Function: add_resource_node. + * + * Stubbed add_resource_node added to satisfy reference in unused + * `host_read_resource_file' in `hunt_cnf.c'. Needed in order to make trapper + * SoftPC link when using Microsoft `config'. + * ========================================================================== + */ +GLOBAL LineNode * +add_resource_node(CHAR *str) +{ + always_trace0("Stubbed add_resource_node called"); + return((LineNode *) NULL); +} + +#endif /* HUNTER */ + +/* + * =========================================================================== + * LOCAL FUNCTIONS + * =========================================================================== + */ + +#ifdef HUNTER + +VOID +build_data_table(VOID) +{ + SHORT maxHostID = 0; + OptionDescription *defP; + + /* Don't do it more than once. */ + if (conf_tab != NULL) + return; + + /* Find out how big the table needs to be. */ + for (defP = host_defs; defP->optionName; defP++) + if (defP->hostID > maxHostID) + maxHostID = defP->hostID; + maxHostID++; + + /* Create the table. */ + check_malloc(conf_tab, maxHostID, ConfTabEntry); +} + +VOID +read_trapper_variables(VOID) +{ + CHAR arg[MAXPATHLEN], + *vp; + OptionDescription *defP; + ConfigValues data, + *cvp; + ErrData errData; + + /* Read all the variables required by trapper from the environment. */ + for (defP = host_defs; defP->optionName; defP++) + { + + /* + * Ignore `host_defs' entries designed to override `common_defs' + * entries as we have an empty common_defs table. + */ + if ((defP->flags & C_TYPE_MASK) == C_RECORD_DELETE) + continue; + + /* Get the variable. */ + vp = host_getenv(defP->optionName); + if (vp != NULL) + strcpy(arg, vp); + else + arg[0] = '\0'; + + /* + * Convert variable and store in ConfigValues structure for use by + * validation routine. + */ + convert_arg(arg, defP, &data); + errData.string_1 = arg; + errData.string_2 = defP->optionName; + while (check_value(defP, &data)) + { + if (host_error_ext(EG_BAD_CONF, ERR_QU_CO, &errData) == ERR_CONT) + convert_arg(arg, defP, &data); + } + + /* Store the value in the data table. */ + check_malloc(cvp, 1, ConfigValues); + conf_tab[defP->hostID].data = cvp; + conf_tab[defP->hostID].def = defP; + switch (defP->flags & C_TYPE_MASK) + { + case C_STRING_RECORD: + always_trace2("read_trapper_variables: %s set to %s", + defP->optionName, data.string); + strcpy(cvp->string, data.string); + break; + + case C_NAME_RECORD: + case C_NUMBER_RECORD: + always_trace2("read_trapper_variables: %s set to %d", + defP->optionName, data.index); + cvp->index = data.index; + break; + + default: + break; + } + } +} + +VOID +convert_arg(CHAR *arg, OptionDescription *defP, ConfigValues *dataP) +{ + switch (defP->flags & C_TYPE_MASK) + { + case C_STRING_RECORD: + strcpy(dataP->string, arg); + break; + + case C_NAME_RECORD: + dataP->index = translate_to_value(arg, defP->table); + break; + + case C_NUMBER_RECORD: + dataP->index = atoi(arg); + break; + + default: + (VOID) host_error(EG_OWNUP, ERR_QUIT, "Invalid TYPE"); + break; + } +} + +SHORT +check_value(OptionDescription *defP, ConfigValues *dataP) +{ + SHORT status; + CHAR errbuf[MAXPATHLEN]; + + if (defP->valid) + status = (*defP->valid)(defP->hostID, dataP, defP->table, errbuf); + else + status = C_CONFIG_OP_OK; + return(status); +} + +#endif /* HUNTER */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Read auto close time ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#define APPNAME "Dos Emulation" + +/* These are entries uder "WOW" section in the system registry to control + * LPT and COM devices behaviors. + * + * "PrinterAutoClose=n" -- the printer port will be closed if there are + * not activities on the port for n seconds + * "CommsAutoClose=n" -- the comm port will be closed(suspended" if there + * there are not activities on the port for + * n s. 0 means auto close is disabled. + * "LPT_timeout=n" -- the printer port will be flushed every n seconds + * "COM_SyncWrite=[0,1]" -- if 0, write to comm port(tx) if performed in + * async way(using overlapped i/o). If 1, then + * data will be written to the port in synchrounously. + * "COM_TxBuffer_Size=n" -- comm tx queue buffer size. It also used to control + * the tx threshold -- setting the buffer size to + * 1 effectively disables tx queuing. + */ +struct { char *keyword; int def; } ProfileStrings[] = +{ + { "PrinterAutoClose", 15 }, + { "CommsAutoClose", 0 }, + { "LPT_timeout", 15}, + { "COM_SyncWrite", }, + { "COM_TxBuffer_Size", 200} +}; + +int read_profile_int(int index) +{ + CHAR CmdLine[100]; + ULONG CmdLineSize = 100; + HKEY hWowKey; + int Value; + + ASSERT((unsigned int) index < PROFILE_MAX_INDEX); + /* make sure we have right index constants */ + ASSERT(PROFILE_LPT_AUTOCLOSE_DELAY == 0 && + PROFILE_COM_AUTOCLOSE_DELAY == 1 && + PROFILE_LPT_AUTOFLUSH_DELAY == 2 && + PROFILE_COM_SYNCWRITE == 3 && + PROFILE_COM_TXBUFFER_SIZE == 4); + + if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\WOW", + 0, + KEY_QUERY_VALUE, + &hWowKey + ) != 0) + { + /* wow key doesn't exist, use default value */ + return(ProfileStrings[index].def); + } + + if (RegQueryValueEx (hWowKey, + ProfileStrings[index].keyword, + NULL, + NULL, + (LPBYTE)&CmdLine, + &CmdLineSize) != 0) + { + /* if the value doesn't exist, use the default value */ + Value = ProfileStrings[index].def; + } + else + Value = (int)atoi(CmdLine); + + RegCloseKey (hWowKey); + + return Value; +} + + + +#ifdef LIM +boolean get_lim_configuration_data(PLIM_CONFIG_DATA buffer) +{ + if (lim_config_data.initialized){ + *buffer = lim_config_data; + return TRUE; + } + else + return FALSE; +} +#endif + + +#ifdef MONITOR +/* this function returns the backfill starting segment to monitor + * + * VERT IMPORTANT !!!! + * the backfill segment must be available before sas_init. + * + */ + +unsigned short get_lim_backfill_segment(void) +{ +#ifdef LIM + if (lim_config_data.initialized) + return lim_config_data.base_segment; + else + return 640 * 1024 / 16; +#else + return 640 * 1024 / 16; +#endif + +} +#endif + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Get VDM Memory Size :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +#define REGISTRY_BUFFER_SIZE 512 + +// Returns the size in K. + +ULONG +GetVDMSize (BOOL fwow) +{ + CHAR CmdLine[REGISTRY_BUFFER_SIZE]; + PCHAR pCmdLine,KeywordName; + ULONG CmdLineSize = REGISTRY_BUFFER_SIZE; + HKEY WowKey; + + // + // Get Vdm size + // + + if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\WOW", + 0, + KEY_QUERY_VALUE, + &WowKey + ) != 0){ + return GetDefaultVDMSize (fwow); // returns in K + } + + if (fwow) { + KeywordName = "wowsize" ; + } else { + KeywordName = "size" ; + } + + if (RegQueryValueEx (WowKey, + KeywordName, + NULL, + NULL, + (LPBYTE)&CmdLine, + &CmdLineSize) != 0){ + RegCloseKey (WowKey); + return GetDefaultVDMSize (fwow); // returns in K + } + + RegCloseKey (WowKey); + + CmdLineSize = 1024L * atoi(CmdLine); + + if (CmdLineSize == 0) + CmdLineSize = GetDefaultVDMSize (fwow); // returns in K + + return (CmdLineSize); + } + +#define VDM_SMALL_SYSTEM (12*1024*1024) +#define VDM_MEDIUM_SYSTEM (16*1024*1024) + +ULONG +GetDefaultVDMSize ( BOOL fwow ) +{ + MEMORYSTATUS MemoryStatus; + + GlobalMemoryStatus (&MemoryStatus); + + // + // System Size < 12Mb is small = VDM Size = 3MB + // System Size = 12-16 is medium = VDM Size = 6MB + // System Size = > 16 is large = VDM Size = 8Mb + // + + if (MemoryStatus.dwTotalPhys < VDM_SMALL_SYSTEM ) + return 8L * 1024L; + + if (MemoryStatus.dwTotalPhys <= VDM_MEDIUM_SYSTEM ) + return 12L * 1024L; + else + return 16L * 1024L; +} diff --git a/private/mvdm/softpc.new/host/src/copy_fnc.c b/private/mvdm/softpc.new/host/src/copy_fnc.c new file mode 100644 index 000000000..a7e4382df --- /dev/null +++ b/private/mvdm/softpc.new/host/src/copy_fnc.c @@ -0,0 +1,195 @@ +/* static char SccsID[] = " @(#)copy_func.c 1.6 6/24/91 Copyright Insignia Solutions Ltd."; */ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "host_def.h" +#include "insignia.h" +#include "xt.h" + +void +bwdcopy( + char *src, + char *dest, + int len + ) +{ +#if 0 +register int loop; + for(loop = 0; loop < len; loop++) + *dest-- = *src--; + +#else + int i; + + i = len - 1; + memcpy(dest - i , src - i, len); + +#endif +} + + +void +bwd_dest_copy( + char *src, + char *dest, + int len + ) +{ + int loop; + + for(loop = 0; loop < len; loop++) + *dest-- = *src++; +} + + +void +memfill( + unsigned char data, + unsigned char *l_addr_in, + unsigned char *h_addr_in + ) +{ + unsigned int len; + + len = h_addr_in + 1 - l_addr_in; + memset(l_addr_in, data, len); + +#if 0 + unsigned int data4; + unsigned char *l_addr = l_addr_in; + unsigned char *h_addr = h_addr_in; + unsigned int *l_addr4,*h_addr4; + + l_addr4 = (unsigned int *)(((unsigned int)l_addr+3) & (~3)); + h_addr4 = (unsigned int *)(((unsigned int)h_addr+1) & (~3)); + if(h_addr4 > l_addr4) + { + data4 = data*0x01010101; // 0x61 * 0x01010101 = 0x61616161 + for(;(unsigned int *)l_addr < l_addr4;l_addr++) + *l_addr = data; + do { + *l_addr4++ = data4; + } while (h_addr4 > l_addr4); + + l_addr = (unsigned char *)l_addr4; + } + for(;l_addr <= h_addr;l_addr++)*l_addr = data; +#endif +} + +void +fwd_word_fill( + unsigned short data, + unsigned char *l_addr_in, + int len + ) +{ + unsigned int data4, count; + unsigned char *l_addr = l_addr_in; + unsigned char *h_addr = l_addr_in+(len<<1); + unsigned int *l_addr4,*h_addr4; + + l_addr4 = (unsigned int *)(((unsigned int)l_addr+3) & (~3)); + h_addr4 = (unsigned int *)(((unsigned int)h_addr) & (~3)); +#ifdef LITTLEND + data = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); +#endif + if(h_addr4 > l_addr4) + { + switch((unsigned char *)l_addr4-l_addr) + { + case 3: + data = (data>>8) | (data<<8); + *l_addr++ = (unsigned char)(data); + case 2: + *(unsigned short *)l_addr = data; + break; + case 1: + data = (data>>8) | (data<<8); + *l_addr = (unsigned char)data; + } + data4 = data+(data<<16); + +#if 0 + do *l_addr4++ = data4; while (h_addr4 > l_addr4); + l_addr = (unsigned char *)l_addr4; +#else + count = h_addr4 - l_addr4; + RtlFillMemoryUlong(l_addr4, count, data4); + l_addr = (unsigned char *)l_addr4; + l_addr += count; +#endif + + } + switch(h_addr-l_addr) + { + case 5: +/* + data = (data>>8) | (data<<8); +*/ + data = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); + *l_addr++ = (unsigned char)data; + *(unsigned int *)l_addr = data | (data<<16); + break; + case 7: +/* + data = (data>>8) | (data<<8); +*/ + data = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); + *l_addr++ = (unsigned char)data; + case 6: + *l_addr++ = (unsigned char)data; + *l_addr++ = data >> 8; + case 4: + *l_addr++ = (unsigned char)data; + *l_addr++ = data >> 8; + *l_addr++ = (unsigned char)data; + *l_addr++ = data >> 8; + break; + case 3: +/* + data = (data>>8) | (data<<8); +*/ + data = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); + *l_addr++ = (unsigned char)(data); + case 2: + *l_addr++ = (unsigned char)data; + *l_addr++ = data >> 8; + break; + case 1: +/* + data = (data>>8) | (data<<8); +*/ + data = ((data >> 8) & 0xff) | ((data << 8) & 0xff00); + *l_addr = (unsigned char)data; + } +} + + + + +void +memset4( + unsigned int data, + unsigned int *laddr, + unsigned int count + ) +{ +#if 0 + while( count -- ) + { + *laddr++ = data; + } +#else + + /* + * The argument, count, as passed to this function is the number of 4-byte + * items to fill, all RtlFill type functions need their count in bytes, so + * multiply count by 4. (JJS - 6/9/95). + */ + RtlFillMemoryUlong(laddr, count << 2, data); + +#endif +} diff --git a/private/mvdm/softpc.new/host/src/cpucstbs.c b/private/mvdm/softpc.new/host/src/cpucstbs.c new file mode 100644 index 000000000..b70c14339 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/cpucstbs.c @@ -0,0 +1,32 @@ +#ifndef MONITOR +#ifdef A3CPU + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "insignia.h" +#include "host_def.h" +#include "xt.h" +#include "ica.h" + +void npx_interrupt_line_waggled() +{ + ica_hw_interrupt(1, 5, 1); +} + +// MIPS interface from CPU cacheflush request +void cacheflush(long base_addr, long length) +{ + // should check return, but what is correct action (Exit??) if failure? + NtFlushInstructionCache(GetCurrentProcess(), (PVOID) base_addr, length); +} + +void host_sigio_event() +{ +} + + +#endif /* A3CPU */ +#endif /* ! MONITOR */ diff --git a/private/mvdm/softpc.new/host/src/fprt.c b/private/mvdm/softpc.new/host/src/fprt.c new file mode 100644 index 000000000..0968d5f66 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/fprt.c @@ -0,0 +1,233 @@ +#include "windows.h" +#include "insignia.h" +#include "stdlib.h" +#include "stdio.h" +#include "stdarg.h" +#ifdef HUNTER +#include "nt_hunt.h" +#endif /* HUNTER */ + +void OutputString(char *); + +int _CRTAPI1 printf(const char *str, ...) +{ +#ifndef PROD + va_list ap; + char buf[500]; + + va_start(ap,str); + vsprintf(buf, str, ap); + OutputString(buf); + va_end(ap); +#endif + return(0); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static HANDLE pipe=NULL; + +void OutputString(char *str) +{ +#ifndef PROD + char StrSizeStr[2]; + int StrSize; + DWORD BytesWritten; + + /*............................................ Connect to debug pipe */ + + if(pipe == NULL && getenv("PIPE") != NULL) + { + pipe = CreateFile(getenv("PIPE"),GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL); + + if(pipe == (HANDLE) -1) + OutputDebugString("ntvdm : Failed to connect to debug pipe\n"); + } + + /*.................................................... Output string */ + + if(pipe != NULL && pipe != (HANDLE) -1) + { + StrSize = strlen(str); + StrSizeStr[0] = (char) (StrSize % 256); + StrSizeStr[1] = (char) (StrSize / 256); + + WriteFile(pipe, StrSizeStr, 2, &BytesWritten, NULL); + WriteFile(pipe, str, StrSize, &BytesWritten, NULL); + } + else + OutputDebugString(str); + +#endif +#ifdef HUNTER + if (TrapperDump != (HANDLE) -1) + WriteFile(TrapperDump, str, strlen(str), &BytesWritten, NULL); +#endif /* HUNTER */ +} + +#define WACKY_INPUT "[BOB&SIMON'SCHEESYINPUT]" +#define WACKY_INPUTLEN 0xff + +#define INPUT_API_SIG 0xdefaced + +VOID InputString(char *str, int len) +{ +#ifndef PROD + + char input_request[2]; + DWORD BytesWritten, BytesRead; + int StringSize; + UNALIGNED DWORD *addsig; + char *inorout; + IMPORT ULONG DbgPrompt(char *, char *, ULONG); + + if(pipe != NULL && pipe != (HANDLE) -1) + { + input_request[0] = (char)0xff; input_request[1] = (char)0xff; + WriteFile(pipe, input_request, 2, &BytesWritten, NULL); + + ReadFile(pipe, str, 2, &BytesRead, NULL); + StringSize = (str[0]&0xff) + ((str[1]&0xff)*256); + + if(StringSize >= len) + OutputDebugString("ntvdm : PIPE BUFFER OVERFLOW [FATAL]\n"); + + ReadFile(pipe, str, StringSize, &BytesRead, NULL); + } + else + { +/* + We used to do this... + DbgPrompt("",str,len); + but foozle dust now does this... + + Call OutputDebugString with the following: + + "Message" | 0xdefaced | len | inBuffer + +where "Message" is printed + 0xdefaced is a magic (DWORD) signature + len is a byte length of,,, + inBuffer which the reply to 'Message will appear in. +*/ + /* do this so we can add prompt passing if we wish */ + StringSize = strlen("") + 1; + inorout = malloc(len + StringSize + 5); + if (!inorout) + { + printf("\nmemory allocation failure - getting input via kd\n"); + DbgPrompt("NTVDM>> ", str, len); + return; + } + strcpy(inorout, ""); + addsig = (PDWORD)&inorout[StringSize]; + *addsig = INPUT_API_SIG; + *(inorout + StringSize+4) = (BYTE)len; + *(inorout + StringSize+5) = (BYTE)0xff; // success flag + OutputDebugString(inorout); + // check for no debugger or debugger that can't speak foozle + if (*(inorout + StringSize + 5) == 0xff) + DbgPrompt("", str, len); + else + strcpy(str, inorout + StringSize + 5); + free(inorout); + } + +#endif +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int _CRTAPI2 fprintf(FILE *tf, const char *str, ...) +{ +#ifndef PROD + va_list ap; + char buf[500]; + + if (getenv("TRACE") == NULL) //JonLu request to limit debugs + return(0); + + va_start(ap,str); + vsprintf(buf, str, ap); + va_end(ap); + OutputString(buf); +#endif + return(0); +} + +char *nt_fgets(char *buffer, int len, void *input_stream) +{ + /* Get Line from debug terminal */ + buffer[0] = 0; + InputString(buffer,len); + + return(buffer); +} + +char *nt_gets(char *buffer) +{ + return(nt_fgets(buffer, 500, (void *) 0)); +} + +#ifndef HUNTER +char * _CRTAPI1 fgets(char *buffer, int len, FILE *input_stream) +{ + int blen; + + // If not processing call to STDIN pass on to standard library function + if(input_stream != stdin) + { + char *ptr = buffer; + int chr; + + while(--len && (chr = fgetc(input_stream)) != EOF) + { + *ptr++ = (char) chr; + if(chr == '\n') break; + } + + *ptr = (char) 0; + return(chr == EOF ? NULL : buffer); + + } + + // clear buffer... + for(blen = 0; blen < len; blen++) + buffer[blen] = 0; + nt_fgets(buffer, len, input_stream); + blen = strlen(buffer); + if (blen + 1 < len) + { + buffer[blen] = '\n'; /* fgets adds newline */ + buffer[blen+1] = '\0'; + } + return(buffer); +} + +char * _CRTAPI1 gets(char *buffer) +{ + return(nt_fgets(buffer, 500, (void *) 0)); +} + +int _CRTAPI1 puts(const char *buffer) +{ + OutputString((char *)buffer); + return(1); +} + +size_t _CRTAPI1 fwrite(const void *buf, size_t size, size_t len, FILE *stream) +{ + char *tmp_buf; // Screw the compiler into avoiding const chk + + tmp_buf = (char *)((DWORD)buf); + + tmp_buf[len] = 0; // Bullshit write into a const ptr! +#ifndef PROD + OutputString((char *)buf); +#endif /* PROD */ + return(len); +} +#endif /* HUNTER */ diff --git a/private/mvdm/softpc.new/host/src/makefile b/private/mvdm/softpc.new/host/src/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/mvdm/softpc.new/host/src/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/mvdm/softpc.new/host/src/makefile.inc b/private/mvdm/softpc.new/host/src/makefile.inc new file mode 100644 index 000000000..a9dd941dc --- /dev/null +++ b/private/mvdm/softpc.new/host/src/makefile.inc @@ -0,0 +1,6 @@ +#dummy file to be included + +{obj\$(TARGET_DIRECTORY)\}fprt.obj : fprt.c + +$(SOFTPC_DEST)\obj\$(TARGET_DIRECTORY)\fprt.obj : obj\$(TARGET_DIRECTORY)\fprt.OBJ + copy $** $@ diff --git a/private/mvdm/softpc.new/host/src/nt_aorc.c b/private/mvdm/softpc.new/host/src/nt_aorc.c new file mode 100644 index 000000000..71d5e0bd2 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_aorc.c @@ -0,0 +1,861 @@ +/* +============================== nt_a_or_c.c =================================== + + This file provides a crude means of mapping a cpu specific function + to a generically used function. Microsoft libraries to which we do not + have the source, call getXX and setXX functions directly and thus a mapping + is required if a C emulator is built or an assembly language variant is + used. + + For example: + + If CCPU is defined, then getAX() maps to c_getAX(), + If A3CPU is defined, then getAX() maps to a3_getAX(), + + Unfortunately, this does not allow a pigger to build. + + Andy Watson 3/11/94 + +============================================================================== +*/ + +#include "insignia.h" +#include "host_def.h" +#define CPU_PRIVATE +#include "cpu4.h" +#include "sas.h" + +#ifdef CCPU + +/* + * + * CCPU interface to the emulator registers. + * + */ + +#undef getAL +GLOBAL half_word getAL() +{ + return c_getAL(); +} + +#undef getBL +GLOBAL half_word getBL() +{ + return c_getBL(); +} + +#undef getCL +GLOBAL half_word getCL() +{ + return c_getCL(); +} + +#undef getDL +GLOBAL half_word getDL() +{ + return c_getDL(); +} + +#undef getAH +GLOBAL half_word getAH() +{ + return c_getAH(); +} + +#undef getBH +GLOBAL half_word getBH() +{ + return c_getBH(); +} + +#undef getCH +GLOBAL half_word getCH() +{ + return c_getCH(); +} + +#undef getDH +GLOBAL half_word getDH() +{ + return c_getDH(); +} + +#undef getAX +GLOBAL word getAX() +{ + return c_getAX(); +} + +#undef getBX +GLOBAL word getBX() +{ + return c_getBX(); +} + +#undef getCX +GLOBAL word getCX() +{ + return c_getCX(); +} + +#undef getDX +GLOBAL word getDX() +{ + return c_getDX(); +} + +#undef getSP +GLOBAL word getSP() +{ + return c_getSP(); +} + +#undef getBP +GLOBAL word getBP() +{ + return c_getBP(); +} + +#undef getSI +GLOBAL word getSI() +{ + return c_getSI(); +} + +#undef getDI +GLOBAL word getDI() +{ + return c_getDI(); +} + +#undef getIP +GLOBAL word getIP() +{ + return c_getIP(); +} + +#undef getEIP +GLOBAL IU32 getEIP() +{ + return c_getEIP(); +} + +#undef getESP +GLOBAL IU32 getESP() +{ + return c_getESP(); +} + +#undef getEFLAGS +GLOBAL IU32 getEFLAGS() +{ + return c_getEFLAGS(); +} + + + +#undef GetInstructionPointer +GLOBAL IU32 GetInstructionPointer() +{ + return (IU32) c_getIP(); +} + +#undef getCS +GLOBAL word getCS() +{ + return c_getCS(); +} + +#undef getDS +GLOBAL word getDS() +{ + return c_getDS(); +} + +#undef getES +GLOBAL word getES() +{ + return c_getES(); +} + +#undef getSS +GLOBAL word getSS() +{ + return c_getSS(); +} + + +#undef getAF +GLOBAL word getAF() +{ + return c_getAF(); +} + +#undef getCF +GLOBAL word getCF() +{ + return c_getCF(); +} + +#undef getDF +GLOBAL word getDF() +{ + return c_getDF(); +} + +#undef getIF +GLOBAL word getIF() +{ + return c_getIF(); +} + +#undef getOF +GLOBAL word getOF() +{ + return c_getOF(); +} + +#undef getPF +GLOBAL word getPF() +{ + return c_getPF(); +} + +#undef getSF +GLOBAL word getSF() +{ + return c_getSF(); +} + +#undef getTF +GLOBAL word getTF() +{ + return c_getTF(); +} + +#undef getZF +GLOBAL word getZF() +{ + return c_getZF(); +} + +#undef getMSW +GLOBAL word getMSW() +{ + return c_getMSW(); +} +#undef getCPL +GLOBAL word getCPL() +{ + return c_getCPL(); +} + +#undef setAL +GLOBAL VOID setAL(val) +half_word val; +{ + setAX( (getAX() & 0xFF00) | (val & 0xFF) ); +} + + +#undef setCL +GLOBAL VOID setCL(val) +half_word val; +{ + setCX( (getCX() & 0xFF00) | (val & 0xFF) ); +} + + +#undef setDL +GLOBAL VOID setDL(val) +half_word val; +{ + setDX( (getDX() & 0xFF00) | (val & 0xFF) ); +} + + +#undef setBL +GLOBAL VOID setBL(val) +half_word val; +{ + setBX( (getBX() & 0xFF00) | (val & 0xFF) ); +} + + +#undef setAH +GLOBAL VOID setAH(val) +half_word val; +{ + setAX( getAL() | ((val & 0xFF) << 8) ); +} + + +#undef setCH +GLOBAL VOID setCH(val) +half_word val; +{ + setCX( getCL() | ((val & 0xFF) << 8) ); +} + + +#undef setDH +GLOBAL VOID setDH(val) +half_word val; +{ + setDX( getDL() | ((val & 0xFF) << 8) ); +} + + +#undef setBH +GLOBAL VOID setBH(val) +half_word val; +{ + setBX( getBL() | ((val & 0xFF) << 8) ); +} + + +#undef setAX +GLOBAL VOID setAX(val) +word val; +{ + c_setAX(val); +} + +#undef setBX +GLOBAL VOID setBX(val) +word val; +{ + c_setBX(val); +} + + +#undef setCX +GLOBAL VOID setCX(val) +word val; +{ + c_setCX(val); +} + + +#undef setDX +GLOBAL VOID setDX(val) +word val; +{ + c_setDX(val); +} + + + +#undef setSP +GLOBAL VOID setSP(val) +word val; +{ + c_setSP(val); +} + + +#undef setBP +GLOBAL VOID setBP(val) +word val; +{ + c_setBP(val); +} + + +#undef setSI +GLOBAL VOID setSI(val) +word val; +{ + c_setSI(val); +} + + +#undef setDI +GLOBAL VOID setDI(val) +word val; +{ + c_setDI(val); +} + + +#undef setIP +GLOBAL VOID setIP(val) +word val; +{ + c_setIP(val); +} + +#undef setES +GLOBAL setES(val) +word val; +{ + return c_setES(val); +} + + +#undef setCS +GLOBAL setCS(val) +word val; +{ + return c_setCS(val); +} + +#undef setSS +GLOBAL setSS(val) +word val; +{ + return c_setSS(val); +} + + +#undef setDS +GLOBAL setDS(val) +word val; +{ + return c_setDS(val); +} + + + +#undef setCF +GLOBAL VOID setCF(val) +word val; +{ + c_setCF(val); +} + + +#undef setPF +GLOBAL VOID setPF(val) +word val; +{ + c_setPF(val); +} + + +#undef setAF +GLOBAL VOID setAF(val) +word val; +{ + c_setAF(val); +} + + +#undef setZF +GLOBAL VOID setZF(val) +word val; +{ + c_setZF(val); +} + + +#undef setSF +GLOBAL VOID setSF(val) +word val; +{ + c_setSF(val); +} + + +#undef setTF +GLOBAL VOID setTF(val) +word val; +{ + c_setTF(val); +} + + +#undef setIF +GLOBAL VOID setIF(val) +word val; +{ + c_setIF(val); +} + + +#undef setDF +GLOBAL VOID setDF(val) +word val; +{ + c_setDF(val); +} + + +#undef setOF +GLOBAL VOID setOF(val) +word val; +{ + c_setOF(val); +} + +#undef setMSW +GLOBAL VOID setMSW(val) +word val; +{ + c_setMSW(val); +} + + +#undef setEIP +GLOBAL VOID setEIP(val) +IU32 val; +{ + c_setEIP(val); +} + +#undef setEFLAGS +GLOBAL void setEFLAGS(val) +IU32 val; +{ + c_setEFLAGS(val); +} + +#if 0 +#undef setFLAGS +GLOBAL void setFLAGS(val) +IU32 val; +{ + c_setEFLAGS(val); +} +#endif + +#undef setESP +void setESP(val) +IU32 val; +{ + c_setESP(val); +} + + +/* fiddle for building prod version */ + +#undef getSS_BASE +GLOBAL word getSS_BASE() +{ + return c_getSS_BASE(); +} + +#undef getSS_AR +GLOBAL word getSS_AR() +{ + return c_getSS_AR(); +} + +#undef setSS_BASE_LIMIT_AR +void setSS_BASE_LIMIT_AR(base,limit,ar) +IU32 base,limit; +IU16 ar; +{ + c_setSS_BASE_LIMIT_AR(base,limit,ar); +} + + +#endif /* CCPU */ + +#ifdef CPU_40_STYLE +#if defined(PROD) && !defined(CCPU) + + +#undef setAL +void setAL(IU8 val) {(*(Cpu.SetAL))(val); } +#undef setAH +void setAH(IU8 val) {(*(Cpu.SetAH))(val); } +#undef setAX +void setAX(IU16 val) {(*(Cpu.SetAX))(val); } +#undef setBL +void setBL(IU8 val) {(*(Cpu.SetBL))(val); } +#undef setBH +void setBH(IU8 val) {(*(Cpu.SetBH))(val); } +#undef setBX +void setBX(IU16 val) {(*(Cpu.SetBX))(val); } +#undef setCL +void setCL(IU8 val) {(*(Cpu.SetCL))(val); } +#undef setCH +void setCH(IU8 val) {(*(Cpu.SetCH))(val); } +#undef setCX +void setCX(IU16 val) {(*(Cpu.SetCX))(val); } +#undef setDL +void setDL(IU8 val) {(*(Cpu.SetDL))(val); } +#undef setDH +void setDH(IU8 val) {(*(Cpu.SetDH))(val); } +#undef setDX +void setDX(IU16 val) {(*(Cpu.SetDX))(val); } +#undef setSI +void setSI(IU16 val) {(*(Cpu.SetSI))(val); } +#undef setDI +void setDI(IU16 val) {(*(Cpu.SetDI))(val); } +#undef setSP +void setSP(IU16 val) {(*(Cpu.SetSP))(val); } +#undef setBP +void setBP(IU16 val) {(*(Cpu.SetBP))(val); } +#undef setIP +void setIP(IU16 val) {(*(Cpu.SetIP))(val); } +#undef setCS +void setCS(IU16 val) {(*(Cpu.SetCS))(val); } +#undef setSS +void setSS(IU16 val) {(*(Cpu.SetSS))(val); } +#undef setDS +void setDS(IU16 val) {(*(Cpu.SetDS))(val); } +#undef setES +void setES(IU16 val) {(*(Cpu.SetES))(val); } +#undef setFS +void setFS(IU16 val) {(*(Cpu.SetFS))(val); } +#undef setGS +void setGS(IU16 val) {(*(Cpu.SetGS))(val); } + + +#undef setEAX +void setEAX(val) {(*(Cpu.SetEAX))(val); } +#undef setEBX +void setEBX(val) {(*(Cpu.SetEBX))(val); } +#undef setECX +void setECX(val) {(*(Cpu.SetECX))(val); } +#undef setEDX +void setEDX(val) {(*(Cpu.SetEDX))(val); } +#undef setESI +void setESI(val) {(*(Cpu.SetESI))(val); } +#undef setEDI +void setEDI(val) {(*(Cpu.SetEDI))(val); } +#undef setESP +void setESP(val) {(*(Cpu.SetESP))(val); } +#undef setEBP +void setEBP(val) {(*(Cpu.SetEBP))(val); } +#undef setEIP +void setEIP(val) {(*(Cpu.SetEIP))(val); } + + + +#undef setEFLAGS +void setEFLAGS(val) {(*(Cpu.SetEFLAGS))(val); } +#undef setFLAGS +void setFLAGS(val) {(*(Cpu.SetEFLAGS))(val); } +#undef setSTATUS +void setSTATUS(val) {(*(Cpu.SetSTATUS))(val); } +#undef setIOPL +void setIOPL(val) {(*(Cpu.SetIOPL))(val); } +#undef setMSW +void setMSW(val) {(*(Cpu.SetMSW))(val); } +#undef setCR0 +void setCR0(val) {(*(Cpu.SetCR0))(val); } +#undef setCR2 +void setCR2(val) {(*(Cpu.SetCR2))(val); } +#undef setCR3 +void setCR3(val) {(*(Cpu.SetCR3))(val); } +#undef setCF +void setCF(IU16 val) {(*(Cpu.SetCF))(val); } +#undef setPF +void setPF(IU16 val) {(*(Cpu.SetPF))(val); } +#undef setAF +void setAF(IU16 val) {(*(Cpu.SetAF))(val); } +#undef setZF +void setZF(IU16 val) {(*(Cpu.SetZF))(val); } +#undef setSF +void setSF(IU16 val) {(*(Cpu.SetSF))(val); } +#undef setTF +void setTF(IU16 val) {(*(Cpu.SetTF))(val); } +#undef setIF +void setIF(IU16 val) {(*(Cpu.SetIF))(val); } +#undef setDF +void setDF(IU16 val) {(*(Cpu.SetDF))(val); } +#undef setOF +void setOF(IU16 val) {(*(Cpu.SetOF))(val); } +#undef setNT +void setNT(IU16 val) {(*(Cpu.SetNT))(val); } +#undef setRF +void setRF(IU16 val) {(*(Cpu.SetRF))(val); } +#undef setVM +void setVM(IU16 val) {(*(Cpu.SetVM))(val); } +#undef setAC +void setAC(IU16 val) {(*(Cpu.SetAC))(val); } +#undef setPE +void setPE(IU16 val) {(*(Cpu.SetPE))(val); } +#undef setMP +void setMP(IU16 val) {(*(Cpu.SetMP))(val); } +#undef setEM +void setEM(IU16 val) {(*(Cpu.SetEM))(val); } +#undef setTS +void setTS(IU16 val) {(*(Cpu.SetTS))(val); } +#undef setPG +void setPG(IU16 val) {(*(Cpu.SetPG))(val); } +#undef setLDT_SELECTOR +void setLDT_SELECTOR(val) {(*(Cpu.SetLDT_SELECTOR))(val); } +#undef setTR_SELECTOR +void setTR_SELECTOR(val) {(*(Cpu.SetTR_SELECTOR))(val); } + +#undef getAL +IU8 getAL() { return (*(Cpu.GetAL))(); } +#undef getAH +IU8 getAH() { return (*(Cpu.GetAH))(); } +#undef getAX +IU16 getAX() { return (*(Cpu.GetAX))(); } +#undef getBL +IU8 getBL() { return (*(Cpu.GetBL))(); } +#undef getBH +IU8 getBH() { return (*(Cpu.GetBH))(); } +#undef getBX +IU16 getBX() { return (*(Cpu.GetBX))(); } +#undef getCL +IU8 getCL() { return (*(Cpu.GetCL))(); } +#undef getCH +IU8 getCH() { return (*(Cpu.GetCH))(); } +#undef getCX +IU16 getCX() { return (*(Cpu.GetCX))(); } +#undef getDL +IU8 getDL() { return (*(Cpu.GetDL))(); } +#undef getDH +IU8 getDH() { return (*(Cpu.GetDH))(); } +#undef getDX +IU16 getDX() { return (*(Cpu.GetDX))(); } +#undef getSI +IU16 getSI() { return (*(Cpu.GetSI))(); } +#undef getDI +IU16 getDI() { return (*(Cpu.GetDI))(); } +#undef getSP +IU16 getSP() { return (*(Cpu.GetSP))(); } +#undef getBP +IU16 getBP() { return (*(Cpu.GetBP))(); } +#undef getIP +IU16 getIP() { return (*(Cpu.GetIP))(); } +#undef getCS +IU16 getCS() { return (*(Cpu.GetCS))(); } +#undef getSS +IU16 getSS() { return (*(Cpu.GetSS))(); } +#undef getDS +IU16 getDS() { return (*(Cpu.GetDS))(); } +#undef getES +IU16 getES() { return (*(Cpu.GetES))(); } +#undef getFS +IU16 getFS() { return (*(Cpu.GetFS))(); } +#undef getGS +IU16 getGS() { return (*(Cpu.GetGS))(); } + + +#undef getEAX +getEAX() {return ((*(Cpu.GetEAX))()); } +#undef getEBX +getEBX() {return ((*(Cpu.GetEBX))()); } +#undef getECX +getECX() {return ((*(Cpu.GetECX))()); } +#undef getEDX +getEDX() {return ((*(Cpu.GetEDX))()); } +#undef getESI +getESI() {return ((*(Cpu.GetESI))()); } +#undef getEDI +getEDI() {return ((*(Cpu.GetEDI))()); } +#undef getESP +getESP() {return ((*(Cpu.GetESP))()); } +#undef getEBP +getEBP() {return ((*(Cpu.GetEBP))()); } +#undef getEIP +getEIP() {return ((*(Cpu.GetEIP))()); } + + + +#undef getEFLAGS +IU32 getEFLAGS() { return (*(Cpu.GetEFLAGS))(); } +#undef getSTATUS +IU16 getSTATUS() { return (*(Cpu.GetSTATUS))(); } +#undef getIOPL +IU8 getIOPL() { return (*(Cpu.GetIOPL))(); } +#undef getMSW +IU16 getMSW() { return (*(Cpu.GetMSW))(); } +#undef getCR0 +IU32 getCR0() { return (*(Cpu.GetCR0))(); } +#undef getCR2 +IU32 getCR2() { return (*(Cpu.GetCR2))(); } +#undef getCR3 +IU32 getCR3() { return (*(Cpu.GetCR3))(); } +#undef getCF +IBOOL getCF() { return (*(Cpu.GetCF))(); } +#undef getPF +IBOOL getPF() { return (*(Cpu.GetPF))(); } +#undef getAF +IBOOL getAF() { return (*(Cpu.GetAF))(); } +#undef getZF +IBOOL getZF() { return (*(Cpu.GetZF))(); } +#undef getSF +IBOOL getSF() { return (*(Cpu.GetSF))(); } +#undef getTF +IBOOL getTF() { return (*(Cpu.GetTF))(); } +#undef getIF +IBOOL getIF() { return (*(Cpu.GetIF))(); } +#undef getDF +IBOOL getDF() { return (*(Cpu.GetDF))(); } +#undef getOF +IBOOL getOF() { return (*(Cpu.GetOF))(); } +#undef getNT +IBOOL getNT() { return (*(Cpu.GetNT))(); } +#undef getRF +IBOOL getRF() { return (*(Cpu.GetRF))(); } +#undef getVM +IBOOL getVM() { return (*(Cpu.GetVM))(); } +#undef getAC +IBOOL getAC() { return (*(Cpu.GetAC))(); } +#undef getPE +IBOOL getPE() { return (*(Cpu.GetPE))(); } +#undef getMP +IBOOL getMP() { return (*(Cpu.GetMP))(); } +#undef getEM +IBOOL getEM() { return (*(Cpu.GetEM))(); } +#undef getTS +IBOOL getTS() { return (*(Cpu.GetTS))(); } +#undef getET +IBOOL getET() { return (*(Cpu.GetET))(); } +#undef getNE +IBOOL getNE() { return (*(Cpu.GetNE))(); } +#undef getWP +IBOOL getWP() { return (*(Cpu.GetWP))(); } +#undef getPG +IBOOL getPG() { return (*(Cpu.GetPG))(); } +#undef getGDT_BASE +IU32 getGDT_BASE() { return (*(Cpu.GetGDT_BASE))(); } +#undef getGDT_LIMIT +IU16 getGDT_LIMIT() { return (*(Cpu.GetGDT_LIMIT))(); } +#undef getIDT_BASE +IU32 getIDT_BASE() { return (*(Cpu.GetIDT_BASE))(); } +#undef getIDT_LIMIT +IU16 getIDT_LIMIT() { return (*(Cpu.GetIDT_LIMIT))(); } +#undef getLDT_SELECTOR +IU16 getLDT_SELECTOR() { return (*(Cpu.GetLDT_SELECTOR))(); } +#undef getLDT_BASE +IU32 getLDT_BASE() { return (*(Cpu.GetLDT_BASE))(); } +#undef getLDT_LIMIT +IU16 getLDT_LIMIT() { return (*(Cpu.GetLDT_LIMIT))(); } +#undef getTR_SELECTOR +IU16 getTR_SELECTOR() { return (*(Cpu.GetTR_SELECTOR))(); } +#undef getTR_BASE +IU32 getTR_BASE() { return (*(Cpu.GetTR_BASE))(); } +#undef getTR_LIMIT +IU16 getTR_LIMIT() { return (*(Cpu.GetTR_LIMIT))(); } +#undef getTR_AR +IU16 getTR_AR() { return (*(Cpu.GetTR_AR))(); } +#undef setCPL +void setCPL IFN1 (IUH, prot) { ((Cpu.Private)->SetCPL)(prot); } + +#undef getSS_BASE +IU32 getSS_BASE IFN0() +{ return (*((*(Cpu.Private)).GetSS_BASE))(); } + +#undef getSS_AR +IU16 getSS_AR IFN0() +{ return (*((*(Cpu.Private)).GetSS_AR))(); } + +#undef setSS_BASE_LIMIT_AR +IBOOL setSS_BASE_LIMIT_AR IFN3(IU32, base, IU32, limit, IU16, ar) +{ return (*((*(Cpu.Private)).SetSS_BASE_LIMIT_AR))(base, limit, ar); } + + +/*** SAS stuff required for PROD. ***/ + +#undef sas_enable_20_bit_wrapping +void sas_enable_20_bit_wrapping() { (*(Sas.Sas_enable_20_bit_wrapping))(); } +#undef sas_disable_20_bit_wrapping +void sas_disable_20_bit_wrapping() { (*(Sas.Sas_disable_20_bit_wrapping))(); } +#undef sas_twenty_bit_wrapping_enabled +IBOOL sas_twenty_bit_wrapping_enabled() { return (*(Sas.Sas_twenty_bit_wrapping_enabled))(); } +#undef sas_overwrite_memory +void sas_overwrite_memory(IU32 addr, IU32 length) {(*(Sas.Sas_overwrite_memory))(addr, length);} + +#endif /* PROD && !CCPU */ +#endif /* CPU_40_STYLE */ diff --git a/private/mvdm/softpc.new/host/src/nt_bop.c b/private/mvdm/softpc.new/host/src/nt_bop.c new file mode 100644 index 000000000..999663cc4 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_bop.c @@ -0,0 +1,960 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdm.h> +#include "insignia.h" +#include "host_def.h" +#include <nt_thred.h> + +#ifndef MONITOR +#include <gdpvar.h> +#endif + +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST + NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD. + + +DESIGNER : Jim Hatfield + +REVISION HISTORY : +First version : 29th August 1988 +Second version : 18th May 1991 + +MODULE NAME : nt_bop + +SOURCE FILE NAME : nt_bop.c + +PURPOSE : Supply the NT-specific BOP FF operations. + +------------------------------------------------------------------------- +[1.2 DATATYPES FOR [1.1] (if not basic C types)] + + STRUCTURES/TYPEDEFS/ENUMS: + +------------------------------------------------------------------------- +[1.3 INTERMODULE IMPORTS] + + PROCEDURES: None + DATA: None + +------------------------------------------------------------------------- +[1.4 DESCRIPTION OF INTERMODULE INTERFACE] + +[1.4.1 IMPORTED OBJECTS] + +DATA OBJECTS : None + + +/*======================================================================= +[3.INTERMODULE INTERFACE DECLARATIONS] +========================================================================= + +[3.1 INTERMODULE IMPORTS] */ + +/* [3.1.1 #INCLUDES] */ + +#include "stdio.h" + +#include "xt.h" +#include CpuH +#include "sas.h" +#include "error.h" +#include "config.h" +#include "cntlbop.h" +#include "host_bop.h" +#include "demexp.h" +#include "xmsexp.h" +#include "sim32.h" +#include "idetect.h" +#include "bios.h" +#include "nt_reset.h" +#include "nt_eoi.h" +#include <nt_com.h> +#include "yoda.h" + + +/* [3.1.2 DECLARATIONS] */ + +/* [3.2 INTERMODULE EXPORTS] */ + + +/* +5.MODULE INTERNALS : (not visible externally,global internally)] + +[5.1 LOCAL DECLARATIONS] */ + +/* [5.1.1 #DEFINES] */ + +/* [5.1.2 TYPEDEF, STRUCTURE, ENUM DECLARATIONS] */ + +// +// MYFARPROC +// + +typedef ULONG (*MYFARPROC)(); + +/* [5.1.3 PROCEDURE() DECLARATIONS] */ + +/* ----------------------------------------------------------------------- +[5.2 LOCAL DEFINITIONS] + + [5.2.1 INTERNAL DATA DEFINITIONS */ + + +/* [5.2.2 INTERNAL PROCEDURE DEFINITIONS] */ + +/* +7.INTERMODULE INTERFACE IMPLEMENTATION : + */ + +VOID WaitIfIdle(VOID), WakeUpNow(VOID); +VOID to_com_driver(VOID); +VOID call_ica_hw_interrupt(int, half_word, int); +VOID ica_enable_iret_hook(int, int, int); +VOID ica_iret_hook_called(int); + +/* +[7.1 INTERMODULE DATA DEFINITIONS] */ + + +#define SEGOFF(seg,off) (((ULONG)(seg) << 16) + ((off))) + + +/********************************************************/ +/* GLOBALS */ + +void UMBNotify(unsigned char); +VOID demDasdInit(VOID); + +control_bop_array host_bop_table[] = +{ + 0, NULL +}; + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::;:::::: MS BOP stubs :::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +// DOS EMULATION BOP +void MS_bop_0(void) { + ULONG DemCmd; + + DemCmd = (ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), + 1, + FALSE + )); + DemDispatch( DemCmd ); + setIP((USHORT)(getIP() + 1)); + + // we need to prevent the idle system from going off on intensive file + // reads. However, we don't want to disable it for continuous 'Get Time' + // calls (command 0x15). Nor for Get Date (0x15). + if (DemCmd != 0x15 && DemCmd != 0x14) + IDLE_disk(); +} + +// WOW BOP +HANDLE hWOWDll; + +MYFARPROC WOWDispatchEntry; +MYFARPROC WOWInitEntry; +VOID (*pW32HungAppNotifyThread)(UINT) = NULL; + +static BOOL WowModeInitialized = FALSE; + +void MS_bop_1(void) { + + if (!WowModeInitialized) { + //Load the WOW DLL + if ((hWOWDll = SafeLoadLibrary("WOW32")) == NULL) + { +#ifndef PROD + HostDebugBreak(); +#endif + TerminateVDM(); + return; + } + + // Get the init entry point and dispatch entry point + if ((WOWInitEntry = (MYFARPROC)GetProcAddress(hWOWDll, "W32Init")) == NULL) + { +#ifndef PROD + HostDebugBreak(); +#endif + FreeLibrary(hWOWDll); + TerminateVDM(); + return; + } + + if ((WOWDispatchEntry = GetProcAddress(hWOWDll, "W32Dispatch")) == NULL) + { +#ifndef PROD + HostDebugBreak(); +#endif + FreeLibrary(hWOWDll); + TerminateVDM(); + return; + } + + //Get Comms functions + if ((GetCommHandle = (GCHfn) GetProcAddress(hWOWDll, "GetCommHandle")) == NULL) + { +#ifndef PROD + HostDebugBreak(); +#endif + FreeLibrary(hWOWDll); + TerminateVDM(); + return; + } + + if ((GetCommShadowMSR = (GCSfn) GetProcAddress(hWOWDll, "GetCommShadowMSR")) == NULL) + { +#ifndef PROD + HostDebugBreak(); +#endif + FreeLibrary(hWOWDll); + TerminateVDM(); + return; + } + + //Get hung app Notification routine + pW32HungAppNotifyThread = (VOID(*)(UINT))GetProcAddress( hWOWDll, + "W32HungAppNotifyThread"); + if (!pW32HungAppNotifyThread) + { +#ifndef PROD + HostDebugBreak(); +#endif + FreeLibrary(hWOWDll); + TerminateVDM(); + return; + } + + + // Call the init routine + if ((*WOWInitEntry)() == FALSE) + { +#ifndef PROD + HostDebugBreak(); +#endif + TerminateVDM(); + return; + } + + WowModeInitialized = TRUE; + } + +#if !defined(CPU_40_STYLE) || defined(CCPU) + (*WOWDispatchEntry)(); +#else + // Dispatch to WOW dispatcher + { + static BYTE **AddressOfLocal; + BYTE *localSimulateContext = GLOBAL_SimulateContext; + + AddressOfLocal = &localSimulateContext; + + (*WOWDispatchEntry)(); + + SET_GLOBAL_SimulateContext(localSimulateContext); + + if(AddressOfLocal != &localSimulateContext) + { + //Thread switch detected via stack change, force CPU to + //abort the current fragment, reseting GDP var's refering + //to the host stack + + setEIP(getEIP()); + } + } +#endif /* CPU_40_STYLE */ +} + + +// XMS BOP +void MS_bop_2(void) { + XMSDispatch((ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), + 1, + FALSE + ))); + + setIP((USHORT)(getIP() + 1)); +} + + +// DEBUGGING BOP +void MS_bop_int3(void) { + +#ifndef PROD + force_yoda(); +#endif +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +// MONITOR DPMI BOP + +void MS_bop_3(void) +{ + IMPORT VOID DpmiDispatch(VOID); + + DpmiDispatch(); +} + +// SCS BOP +/* CMD dispatcher, this BOP will only work in real mode */ + +void MS_bop_4(void) +{ + half_word Command; + IMPORT BOOL CmdDispatch(ULONG); + + sas_load( ((ULONG)getCS()<<4) + getIP(), &Command); + CmdDispatch((ULONG) Command); + setIP((USHORT)(getIP() + 1)); +} + + +// +// MsBop6 - used to dispatch to debugger support functions +// + +void MS_bop_6() +{ + IMPORT VOID DBGDispatch(VOID); + /* + ** All of the parameters for the debugger support + ** should be on the VDMs stack. + */ + DBGDispatch(); +} + +// +// DefaultVrInitialized - calls to VrInitialized (through a pointer to a routine) +// will return FALSE until the VDMREDIR DLL has been successfully loaded and +// initialized +// + +ULONG DefaultVrInitialized(VOID); +ULONG DefaultVrInitialized() { + return FALSE; +} + +// +// publicly accessible routine addresses. These are not expected to be called +// until VrInitialized points at the real VrInitialized routine inside VdmRedir +// + +#if DBG +ULONG DefaultVrError(VOID); +ULONG DefaultVrError() { + printf("MS_bop_7: Error: function called without VDMREDIR loaded!\n"); + HostDebugBreak(); + return 0; +} +MYFARPROC VrDispatch = &DefaultVrError; +MYFARPROC VrInitialized = &DefaultVrInitialized; +MYFARPROC VrReadNamedPipe = &DefaultVrError; +MYFARPROC VrWriteNamedPipe = &DefaultVrError; +MYFARPROC VrIsNamedPipeName = &DefaultVrError; +MYFARPROC VrIsNamedPipeHandle = &DefaultVrError; +MYFARPROC VrAddOpenNamedPipeInfo = &DefaultVrError; +MYFARPROC VrConvertLocalNtPipeName = &DefaultVrError; +MYFARPROC VrRemoveOpenNamedPipeInfo = &DefaultVrError; +#else +MYFARPROC VrDispatch; +MYFARPROC VrInitialized = DefaultVrInitialized; +MYFARPROC VrReadNamedPipe; +MYFARPROC VrWriteNamedPipe; +MYFARPROC VrIsNamedPipeName; +MYFARPROC VrIsNamedPipeHandle; +MYFARPROC VrAddOpenNamedPipeInfo; +MYFARPROC VrConvertLocalNtPipeName; +MYFARPROC VrRemoveOpenNamedPipeInfo; +#endif + +BOOL LoadVdmRedir(VOID); + +VOID +MS_bop_7( + VOID + ) + +/*++ + +Routine Description: + + Calls Vdm Redir Dispatcher. If the VDMREDIR DLL is not loaded, tries to + load it before calling Dispatcher. If the DLL could not be loaded (or + couldn't be loaded in the past) return an ERROR_INVALID_FUNCTION + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + static int VdmRedirLoadState = 0; // tristate: + // 0 = not loaded, first attempt + // 1 = loaded + // 2 = tried loading already, failed + + // + // new: VdmRedir support is now a DLL. Try to load it. If it can't be loaded + // for whatever reason, return an error to the DOS program. Since it is + // trying to call a Redir function, we will return ERROR_INVALID_FUNCTION + // + + switch (VdmRedirLoadState) { + case 0: + + // + // the DLL is not yet loaded. If we can't load it and get the entry + // points for any reason, return ERROR_INVALID_FUNCTION. From now on, + // net support (including DLC, NetBIOS, named pipes and mailslots) will + // not be available to DOS programs in this session (running as part of + // this NTVDM process), but the rest of DOS functionality will be OK + // + + if (LoadVdmRedir()) { + VdmRedirLoadState = 1; + } else { + VdmRedirLoadState = 2; + goto returnError; + } + + // + // fall through to dispatcher in case 1 + // + + case 1: + + // + // VdmRedir is loaded: do it + // + + VrDispatch((ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), + 1, + (UCHAR)(getMSW() & MSW_PE ? TRUE : FALSE) + ))); + break; + + case 2: + + // + // we tried to load VdmRedir once, but the wheels fell off, so we don't + // try it any more - just return an error, OK? + // + +returnError: + setCF(1); + setAX(ERROR_INVALID_FUNCTION); + break; + +#if DBG + default: + printf("MS_bop_7: BAD: VdmRedirLoadState=%d???\n", VdmRedirLoadState); +#endif + } + + // + // irrespective of whether the DLL is/was loaded or not, we must bump the + // VDM ip past the BOP + // + + setIP((USHORT)(getIP() + 1)); +} + +HANDLE hVdmRedir; +BOOL VdmRedirLoaded = FALSE; + +BOOL IsVdmRedirLoaded() { + return VdmRedirLoaded; +} + +BOOL LoadVdmRedir() { + +#if DBG + LPSTR funcName = ""; +#endif + + if (VdmRedirLoaded) { + return TRUE; + } + if (hVdmRedir = SafeLoadLibrary("VDMREDIR")) { + + // + // get addresses of procedures called by functions in dos\dem\demfile.c + // and dos\dem\demhndl.c + // + + if ((VrDispatch = (MYFARPROC)GetProcAddress(hVdmRedir, "VrDispatch")) == NULL) { +#if DBG + funcName = "VrDispatch"; +#endif + goto closeAndReturnError; + } + if ((VrInitialized = (MYFARPROC)GetProcAddress(hVdmRedir, "VrInitialized")) == NULL) { +#if DBG + funcName = "VrInitialized"; +#endif + goto closeAndReturnError; + } + if ((VrReadNamedPipe = (MYFARPROC)GetProcAddress(hVdmRedir, "VrReadNamedPipe")) == NULL) { +#if DBG + funcName = "VrReadNamedPipe"; +#endif + goto closeAndReturnError; + } + if ((VrWriteNamedPipe = (MYFARPROC)GetProcAddress(hVdmRedir, "VrWriteNamedPipe")) == NULL) { +#if DBG + funcName = "VrWriteNamedPipe"; +#endif + goto closeAndReturnError; + } + if ((VrIsNamedPipeName = (MYFARPROC)GetProcAddress(hVdmRedir, "VrIsNamedPipeName")) == NULL) { +#if DBG + funcName = "VrIsNamedPipeName"; +#endif + goto closeAndReturnError; + } + if ((VrIsNamedPipeHandle = (MYFARPROC)GetProcAddress(hVdmRedir, "VrIsNamedPipeHandle")) == NULL) { +#if DBG + funcName = "VrIsNamedPipeHandle"; +#endif + goto closeAndReturnError; + } + if ((VrAddOpenNamedPipeInfo = (MYFARPROC)GetProcAddress(hVdmRedir, "VrAddOpenNamedPipeInfo")) == NULL) { +#if DBG + funcName = "VrAddOpenNamedPipeInfo"; +#endif + goto closeAndReturnError; + } + if ((VrConvertLocalNtPipeName = (MYFARPROC)GetProcAddress(hVdmRedir, "VrConvertLocalNtPipeName")) == NULL) { +#if DBG + funcName = "VrConvertLocalNtPipeName"; +#endif + goto closeAndReturnError; + } + if ((VrRemoveOpenNamedPipeInfo = (MYFARPROC)GetProcAddress(hVdmRedir, "VrRemoveOpenNamedPipeInfo")) == NULL) { +#if DBG + funcName = "VrRemoveOpenNamedPipeInfo"; +#endif + goto closeAndReturnError; + } + VdmRedirLoaded = TRUE; + return TRUE; + } + +closeAndReturnError: + +#if DBG + printf("MS_bop_7: Error: cannot locate entry point %s in VDMREDIR.DLL\n", funcName); +#endif + + CloseHandle(hVdmRedir); + return FALSE; +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::: More MS BOP stubs */ + +void MS_bop_5(void) +{ + IMPORT VOID ms_bop(VOID); + + ms_bop(); +} + +// +// MS_BOP_8 : Third Party Bop +// +void ISV_RegisterModule (BOOL); +void ISV_DeRegisterModule (void); +void ISV_DispatchCall (void); + +void MS_bop_8 (void) +{ + ULONG iFunc; + UCHAR uchMode = getMSW() & MSW_PE ? TRUE : FALSE; + + + // Get the Function Number + iFunc = (ULONG)(*Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), + 1, + uchMode + )); + + switch (iFunc) { + case 0: /* RegisterModule */ + ISV_RegisterModule (uchMode); + break; + case 1: /* DeRegisterModule */ + ISV_DeRegisterModule (); + break; + case 2: /* DispatchCall */ + ISV_DispatchCall (); + break; + default: + setCF(1); + } + setIP((USHORT)(getIP() + 1)); + return; +} + + +// +// MS_BOP_9 : Direct Access Error bop. An app has tried to do something +// dubious. Tell the user about it. Picks up the type of the error from +// AX. +// +void MS_bop_9(void) +{ + host_direct_access_error((ULONG)getAX()); +} + +// +// MS_BOP_A : Idle control from VDD. +// AX == 0: VDD wants VDM to idle. It will (briefly - 10ms) provided it +// has not just seen some counter idle indication. +// AX == 1: VDD wants VDM to wake up if still idling. +// +void MS_bop_A(void) +{ + word control; + + control = getAX(); + + if (control == 0) + WaitIfIdle(); + else + if (control == 1) + WakeUpNow(); +#ifndef PROD + else + printf("NTVDM:Idle control from VDD bop passed bad AX value (%d)\n", control); +#endif +} + + +/* + * DbgBreakPoint Jonle + * A very simple way to break into the debugger from 16 bit + * Apps registers are unmodified + * Uses the safe DbgBreakPoint in ntvdm.c + * On a free build when we are not being debugged, nothing will happen. + * On a checked build when we are not being debugged, access violate + * With debugger running breaks into 32 bit debugger + */ +void MS_bop_B(void) +{ + OutputDebugString("NTVDM:BOP_DBGBREAKPOINT\n"); + DbgBreakPoint(); +} + + +//timing bop + +void MS_bop_C(void) +{ + illegal_bop(); +} + + +/*:::::::::::::::::::::::::::::::::: This bop is used to control iret hooks */ + +void MS_bop_D(void) +{ +#ifdef MONITOR + extern VOID MonitorEndIretHook(VOID); + half_word iret_index; + + + // get iret index + iret_index = *Sim32GetVDMPointer(SEGOFF(getCS(),getIP()), + 1, + (UCHAR)(getPE() ? TRUE : FALSE) + ); + + // Tell ica that an iret bop has been called + ica_iret_hook_called((int) iret_index); + + // + // Clean up stack, and resume normal code path + // + MonitorEndIretHook(); +#else + illegal_bop(); +#endif + +} + +// Notification bop +// currently defined notification code is +// 00 -- config.sys processing completed. +// +extern LARGE_INTEGER CounterStart, FrequenceStart; + +void MS_bop_E(void) +{ + unsigned char code; + + code = getAL(); + if (code == 0) { + UMBNotify(0); + demDasdInit(); + } + else { +#ifndef PROD + printf("Invalid notification bop\n"); +#endif + } +} + + +void MS_bop_F(void) +{ + extern void kb_setup_vectors(void); + + + kb_setup_vectors(); + + +#ifdef MONITOR + + AddrIretBopTable = ( ((ULONG)getDS() << 16) | (ULONG)getDI() ); + +#ifndef PROD + if (getCX() != VDM_RM_IRETBOPSIZE) { + OutputDebugString("NTVDM:spacing != VDM_RM_IRETBOPSIZE\n"); + DebugBreak(); + } +#endif +#endif + + /* + * Now that spckbd is loaded, and the ivt rom vectors are hooked + * we can allow hw interrupts. + */ + // nt_init_event_thread will resume the event thread after it + // sync up BIOS led states with the system + // ResumeThread(ThreadInfo.EventMgr.Handle); + host_ica_lock(); + DelayIrqLine = 0; + if (!ica_restart_interrupts(ICA_SLAVE)) + ica_restart_interrupts(ICA_MASTER); + host_ica_unlock(); + +#ifdef MONITOR + setCF(1); +#else + setCF(0); +#endif +} + + +#define MAX_ISV_BOP 10 + +typedef struct _ISVBOP { + FARPROC fpDispatch; + HANDLE hDll; +} ISVBOP; + +#define MAX_PROC_NAME 64 +char procbuffer [MAX_PROC_NAME]; + +ISVBOP isvbop_table [MAX_ISV_BOP]; + +void ISV_RegisterModule (BOOL fMode) +{ + char *pchDll,*pchInit,*pchDispatch; + HANDLE hDll; + FARPROC DispatchEntry; + FARPROC InitEntry; + ULONG i; + UCHAR uchMode; + + // Check if we have free space in bop table. + for (i=0; i<MAX_ISV_BOP; i++) { + if (isvbop_table[i].hDll == 0) + break; + } + + if (i == MAX_ISV_BOP) { + setCF (1); + setAX(4); + return; + } + + uchMode = fMode ? TRUE : FALSE; + + pchDll = (PCHAR) Sim32GetVDMPointer (SEGOFF(getDS(),getSI()), + 1, + uchMode + ); + if (pchDll == NULL) { + setCF (1); + setAX(1); + return; + } + pchInit = (PCHAR) Sim32GetVDMPointer(SEGOFF(getES(),getDI()), + 1, + uchMode + ); + + pchDispatch = (PCHAR) Sim32GetVDMPointer(SEGOFF(getDS(),getBX()), + 1, + uchMode + ); + if (pchDispatch == NULL) { + setCF (1); + setAX(2); + return; + } + + if ((hDll = SafeLoadLibrary(pchDll)) == NULL){ + setCF (1); + setAX(1); + return; + } + + // Get the init entry point and dispatch entry point + if (pchInit){ + if ((ULONG)pchInit < 64*1024){ + if (strlen (pchInit) >= MAX_PROC_NAME) { + FreeLibrary(hDll); + setCF (1); + setAX(4); + return; + } + strcpy (procbuffer,pchInit); + pchInit = procbuffer; + } + + if ((InitEntry = (MYFARPROC)GetProcAddress(hDll, pchInit)) == NULL){ + FreeLibrary(hDll); + setCF(1); + setAX(3); + return; + } + } + + if ((ULONG)pchDispatch < 64*1024){ + if (strlen (pchDispatch) >= MAX_PROC_NAME) { + FreeLibrary(hDll); + setCF (1); + setAX(4); + return; + } + strcpy (procbuffer,pchDispatch); + pchDispatch = procbuffer; + } + + if ((DispatchEntry = (MYFARPROC)GetProcAddress(hDll, pchDispatch)) == NULL){ + FreeLibrary(hDll); + setCF(1); + setAX(2); + return; + } + + // Call the init routine + if (pchInit) { + (*InitEntry)(); + } + + // Fill up the bop table + isvbop_table[i].hDll = hDll; + isvbop_table[i].fpDispatch = DispatchEntry; + + i++; + + setAX((USHORT)i); + + return; +} + +void ISV_DeRegisterModule (void) +{ + ULONG Handle; + HANDLE hDll; + + Handle = (ULONG)getAX(); + if (Handle == 0 || Handle > MAX_ISV_BOP){ +#ifndef PROD + printf("Invalid BOP Handle Passed to DeRegisterModule"); +#endif + TerminateVDM(); + return; + } + Handle--; + hDll = isvbop_table[Handle].hDll; + FreeLibrary (hDll); + isvbop_table[Handle].hDll = 0; + isvbop_table[Handle].fpDispatch = NULL; + return; +} + +void ISV_DispatchCall (void) +{ + ULONG Handle; + FARPROC DispatchEntry; + + Handle = (ULONG)getAX(); + if (Handle == 0 || Handle > MAX_ISV_BOP){ +#ifndef PROD + printf("Invalid BOP Handle Passed to DispatchCall"); +#endif + TerminateVDM(); + return; + } + Handle--; + + DispatchEntry = isvbop_table[Handle].fpDispatch; + (*DispatchEntry)(); + return; +} + +#ifdef i386 +/* + * "Safe" version of LoadLibrary which preserves floating-point state + * across the load. This is critical on x86 because the FP state being + * preserved is the 16-bit app's state. MSVCRT.DLL is one offender which + * changes the Precision bits in its Dll init routine. + * + * On RISC, this is an alias for LoadLibrary + * + */ +HINSTANCE SafeLoadLibrary(char *name) +{ + HINSTANCE hInst; + BYTE FpuState[108]; + + // Save the 487 state + _asm { + lea ecx, [FpuState] + fsave [ecx] + } + + hInst = LoadLibrary(name); + + // Restore the 487 state + _asm { + lea ecx, [FpuState] + frstor [ecx] + } + + return hInst; +} +#endif //i386 diff --git a/private/mvdm/softpc.new/host/src/nt_cga.c b/private/mvdm/softpc.new/host/src/nt_cga.c new file mode 100644 index 000000000..512ee3ac8 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_cga.c @@ -0,0 +1,1193 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Win32 CGA Graphics Module + * + * Description : + * + * This modules contain the Win32 specific functions required + * to support CGA emulations. + * + * Author : Jerry Sexton (based on module by John Shanly) + * + * Notes : + * + */ + +#include <windows.h> +#include <string.h> + +#include "insignia.h" +#include "host_def.h" + +#include "xt.h" +#include "gvi.h" +#include "gmi.h" +#include "sas.h" +#include "gfx_upd.h" + +#include "error.h" +#include <stdio.h> +#include "trace.h" +#include "debug.h" +#include "config.h" +#include "host_rrr.h" +#include "conapi.h" + +#include "nt_graph.h" +#include "nt_cga.h" +#include "nt_cgalt.h" +#include "nt_det.h" + +#ifdef MONITOR +#include <ntddvdeo.h> +#include "nt_fulsc.h" +#endif /* MONITOR */ + +/* Externs */ + + +extern char *image_buffer; + +/* Statics */ + +static unsigned int cga_med_graph_hi_nyb[256]; +static unsigned int cga_med_graph_lo_nyb[256]; +#ifdef BIGWIN +static unsigned int cga_med_graph_hi_lut_big[256]; +static unsigned int cga_med_graph_mid_lut_big[256]; +static unsigned int cga_med_graph_lo_lut_big[256]; + +static unsigned int cga_med_graph_lut4_huge[256]; +static unsigned int cga_med_graph_lut3_huge[256]; +static unsigned int cga_med_graph_lut2_huge[256]; +static unsigned int cga_med_graph_lut1_huge[256]; +#endif + +/* + * cga_graph_inc_val depends on whether data is interleaved ( EGA/VGA ) + * or not ( CGA ). Currently always interleaved. + */ +#define CGA_GRAPH_INCVAL 4 + +// likewise for TEXT_INCVAL +// for x86 we have 2 bytes per character (char and attr) +// for risc we have 4 bytes per character because of vga interleaving +// +#ifdef MONITOR +#define TEXT_INCVAL 2 +#else +#define TEXT_INCVAL 4 +#endif + + + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Initialise CGA text output ::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_text() +{ + half_word misc; + IMPORT void vga_misc_inb(io_addr, half_word *); + + /*::::::::::::::::::::::::::::::::::::: Tell trace program were we are */ + + sub_note_trace0(HERC_HOST_VERBOSE, "nt_init_text"); + +#ifdef X86GFX +if (sc.ScreenState == WINDOWED) //fullscreen valid - mouse buffer +#endif //X86GFX + closeGraphicsBuffer(); /* Tim Oct 92 */ + +#ifdef MONITOR + vga_misc_inb(0x3cc, &misc); + if (misc & 1) + set_screen_ptr((UTINY *)CGA_REGEN_BUFF); //point screen to regen not planes + else + set_screen_ptr((UTINY *)MDA_REGEN_BUFF); //0xb0000 not 0xb8000 +#endif //MONITOR +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Init CGA mono graph ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_cga_mono_graph() +{ + sub_note_trace0(CGA_HOST_VERBOSE,"nt_init_cga_mono_graph - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Init CGA colour med graphics:::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +void nt_init_cga_colour_med_graph() +{ + static boolean cga_colour_med_deja_vu = FALSE; + unsigned int i, + byte1, + byte2, + byte3, + byte4; + + sub_note_trace0(CGA_HOST_VERBOSE, "nt_init_cga_colour_med_graph"); + + /* Set up bits-per-pixel for current mode. */ + sc.BitsPerPixel = CGA_BITS_PER_PIXEL; + + /* Initialise look-up table for first call. */ + if( !cga_colour_med_deja_vu ) + { + for (i = 0; i < 256; i++) + { + byte1 = i & 0x03; + byte2 = ( i & 0x0C ) >> 2; + byte3 = ( i & 0x30 ) >> 4; + byte4 = ( i & 0xC0 ) >> 6; + +#ifdef BIGEND + cga_med_graph_hi_nyb[i] + = ( byte4 << 24 ) | ( byte4 << 16) + | ( byte3 << 8 ) | byte3; + cga_med_graph_lo_nyb[i] + = ( byte2 << 24 ) | ( byte2 << 16) + | ( byte1 << 8 ) | byte1; + +#ifdef BIGWIN + cga_med_graph_hi_lut_big[i] + = ( byte4 << 24 ) | ( byte4 << 16) + | ( byte4 << 8 ) | byte3; + cga_med_graph_mid_lut_big[i] + = ( byte3 << 24) | ( byte3 << 16 ) + | ( byte2 << 8 ) | byte2; + cga_med_graph_lo_lut_big[i] + = ( byte2 << 24 ) | ( byte1 << 16) + | ( byte1 << 8 ) | byte1; + + cga_med_graph_lut4_huge[i] + = ( byte4 << 24 ) | ( byte4 << 16) + | ( byte4 << 8 ) | byte4; + + cga_med_graph_lut3_huge[i] + = ( byte3 << 24 ) | ( byte3 << 16) + | ( byte3 << 8 ) | byte3; + + cga_med_graph_lut2_huge[i] + = ( byte2 << 24 ) | ( byte2 << 16) + | ( byte2 << 8 ) | byte2; + + cga_med_graph_lut1_huge[i] + = ( byte1 << 24 ) | ( byte1 << 16) + | ( byte1 << 8 ) | byte1; +#endif /* BIGWIN */ +#endif /* BIGEND */ + +#ifdef LITTLEND + cga_med_graph_hi_nyb[i] + = ( byte3 << 24 ) | ( byte3 << 16) + | ( byte4 << 8 ) | byte4; + cga_med_graph_lo_nyb[i] + = ( byte1 << 24 ) | ( byte1 << 16) + | ( byte2 << 8 ) | byte2; + +#ifdef BIGWIN + cga_med_graph_hi_lut_big[i] + = ( byte3 << 24 ) | ( byte4 << 16) + | ( byte4 << 8 ) | byte4; + cga_med_graph_mid_lut_big[i] + = ( byte2 << 24) | ( byte2 << 16 ) + | ( byte3 << 8 ) | byte3; + cga_med_graph_lo_lut_big[i] + = ( byte1 << 24 ) | ( byte1 << 16) + | ( byte1 << 8 ) | byte2; + + cga_med_graph_lut4_huge[i] + = ( byte4 << 24 ) | ( byte4 << 16) + | ( byte4 << 8 ) | byte4; + + cga_med_graph_lut3_huge[i] + = ( byte3 << 24 ) | ( byte3 << 16) + | ( byte3 << 8 ) | byte3; + + cga_med_graph_lut2_huge[i] + = ( byte2 << 24 ) | ( byte2 << 16) + | ( byte2 << 8 ) | byte2; + + cga_med_graph_lut1_huge[i] + = ( byte1 << 24 ) | ( byte1 << 16) + | ( byte1 << 8 ) | byte1; +#endif /* BIGWIN */ +#endif /* LITTLEND */ + + } + + cga_colour_med_deja_vu = TRUE; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::: Init CGA colour hi graphics:::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +void nt_init_cga_colour_hi_graph() +{ + sub_note_trace0(CGA_HOST_VERBOSE,"nt_init_cga_colour_hi_graph"); + + /* Set up bits-per-pixel for current mode. */ + sc.BitsPerPixel = MONO_BITS_PER_PIXEL; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Output CGA text :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +IMPORT int now_height, now_width; + +void nt_text(int ScreenOffset, int ScreenX, int ScreenY, + int len, int height) +{ + int org_clen, org_height; + int clen=len/2; + int lines; + SMALL_RECT WriteRegion; + PBYTE to; + PBYTE pScreenText = get_screen_ptr(ScreenOffset); + + /*:::::::::::::::::::::::::::::::::::::::::::: Output trace information */ + + sub_note_trace6( CGA_HOST_VERBOSE, + "nt_cga_text off=%d x=%d y=%d len=%d h=%d o=%#x", + ScreenOffset, ScreenX, ScreenY, len, height, pScreenText ); + + /*:::::::::::::: Adjust re-paint start location from pixels to characters */ + +#ifndef MONITOR + /* Adjust for RISC parameters being in pixels */ + ScreenX = ScreenX / get_pix_char_width(); + ScreenY = ScreenY / get_host_char_height(); +#endif + + /*:: Clip requested re-paint region to currently selected console buffer */ + + //Clip width + if(ScreenX + clen > now_width) + { + /* Is it possible to adjust the repaint regions width */ + if(ScreenX+1 >= now_width) + { + assert4(NO,"VDM: nt_text() repaint region out of ranged x:%d y:%d w:%d h:%d\n", + ScreenX, ScreenY, clen, height); + return; + } + + //Calculate maximum width + org_clen = clen; + clen = now_width - ScreenX; + + assert2(NO,"VDM: nt_text() repaint region width clipped from %d to %d\n", + org_clen,clen); + } + + //Clip height + if(ScreenY + height > now_height) + { + /* Is it possible to adjust the repaint regions height */ + if(ScreenY+1 >= now_height) + { + assert4(NO,"VDM: nt_text() repaint region out of ranged x:%d y:%d w:%d h:%d\n", + ScreenX, ScreenY, clen, height); + return; + } + + //Calculate maximum height + org_height = height; + height = now_height - ScreenY; + + assert2(NO,"VDM: nt_text() repaint region height clipped from %d to %d\n", + org_height,clen); + } + + if (get_chars_per_line() == 80) + { + // + // Slam Dunk Screen text buffer into shared buffer + // by copying full width blocks instead of subrecs. + // + RtlCopyMemory(&textBuffer[(ScreenY*get_offset_per_line()/2 + ScreenX)*TEXT_INCVAL], + pScreenText, + (((height - 1)*get_offset_per_line()/2) + clen)*TEXT_INCVAL + ); + } + else + { + // the sharing buffer width never changes((80 chars, decided at the + // moment we make the RegisterConsoleVDM call to the console). + // We have to do some transformation when our screen width is not + // 80. + + // note that the sharing buffer has different format on x86 and RISC + // platforms. On x86, a cell is defined as: + // typedef _x86cell { + // byte char; + // byte attributes; + // } + // on RISC, a cell is defined as: + // typedef _RISCcell { + // byte char; + // byte attributes; + // byte reserved_1; + // byte reserved_2; + // } + // the size of each cell was defined by TEXT_INCVAL + // + // this is done so we can use memcpy for each line. + // + + + /*::::::::::::::::::::::::::::::::::::::::::::: Construct output buffer */ + //Start location of repaint region + to = &textBuffer[(ScreenY*80 + ScreenX) * TEXT_INCVAL]; + + for(lines = height; lines; lines--) + { + RtlCopyMemory(to, pScreenText, clen * TEXT_INCVAL); // copy this line + pScreenText += get_chars_per_line() * TEXT_INCVAL; // update src ptr + to += 80 * TEXT_INCVAL; // update dst ptr + } + } + + + /*:::::::::::::::::::::::::::::::::::::::::::::: Calculate write region */ + + WriteRegion.Left = ScreenX; + WriteRegion.Top = ScreenY; + + WriteRegion.Bottom = WriteRegion.Top + height - 1; + WriteRegion.Right = WriteRegion.Left + clen - 1; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::: Display characters */ + + sub_note_trace4( CGA_HOST_VERBOSE, "t=%d l=%d b=%d r=%d", + WriteRegion.Top, WriteRegion.Left, + WriteRegion.Bottom, WriteRegion.Right, + ); + + if(!InvalidateConsoleDIBits(sc.OutputHandle, &WriteRegion)){ + /* + ** We get a rare failure here due to the WriteRegion + ** rectangle being bigger than the screen. + ** Dump out some values and see if it tells us anything. + ** Have also attempted to fix it by putting a delay between + ** the start of a register level mode change and window resize. + */ + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + assert4( NO, "VDM: rectangle t:%d l:%d b:%d r:%d", + WriteRegion.Top, WriteRegion.Left, + WriteRegion.Bottom, WriteRegion.Right + ); + assert2( NO, "VDM: bpl=%d sl=%d", + get_bytes_per_line(), get_screen_length() ); + } + +} /* end of nt_text() */ + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::: Paints CGA graphics for a mono monitor, in a standard window :::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_mono_graph_std(int offset, int screen_x, int screen_y, + int len, int height ) +{ +sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_mono_graph_std off=%d x=%d y=%d len=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, len, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: Paints CGA graphics for a mono monitor, in a big window :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_mono_graph_big(int offset, int screen_x, int screen_y, + int len, int height) +{ +sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_mono_graph_big off=%d x=%d y=%d len=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, len, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: Paints CGA graphics for a mono monitor, in a huge window ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_mono_graph_huge(int offset, int screen_x, int screen_y, + int len, int height) +{ +sub_note_trace5( CGA_HOST_VERBOSE, + "nt_cga_mono_graph_huge off=%d x=%d y=%d len=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, len, height ); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Paints CGA medium res graphics for a colour monitor,in a standard window */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_med_graph_std(int offset, int screen_x, int screen_y, + int len, int height) +{ + UTINY *intelmem_ptr; + ULONG *graph_ptr; + LONG local_len, + bytes_per_scanline, + longs_per_scanline; + ULONG inc; + SMALL_RECT rect; + static int rejections=0; /* Stop floods of rejected messages */ + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_med_graph_std off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + + /* + ** Tim Jan 93, rapid mode changes cause mismatch between update and + ** paint rountines. Ignore paint request when invalid parameter + ** causes crash. + */ + if( screen_y > 400 ){ + assert1( NO, "VDM: med gfx std rejected y=%d\n", screen_y ); + return; + } + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + if( rejections==0 ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + rejections = 1; + } + return; + }else{ + rejections = 0; + } + + /* Clip image to screen */ + if(height > 1 || len > 80) + height = 1; + if (len>80) + len = 80; + + /* Work out the width of a line (ie 640 pixels) in chars and ints. */ + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + + /* Build up DIB. */ + inc = offset & 1 ? 3 : 1; + intelmem_ptr = get_screen_ptr(offset); + graph_ptr = (ULONG *) ((UTINY *) sc.ConsoleBufInfo.lpBitMap + + (screen_y * bytes_per_scanline + screen_x)); + local_len = len; + do + { + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_hi_nyb[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_lo_nyb[*intelmem_ptr]; + graph_ptr++; + + intelmem_ptr += inc; + inc ^= 2; + } + while( --local_len ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (len << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + { + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:: Paints CGA medium res graphics for a colour monitor, in a big window ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_med_graph_big(int offset, int screen_x, int screen_y, + int len, int height) +{ +#ifdef BIGWIN + UTINY *intelmem_ptr; + ULONG *graph_ptr; + LONG local_len, + bytes_per_scanline, + longs_per_scanline; + ULONG inc; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_med_graph_big off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height); + + /* + ** Tim Jan 93, rapid mode changes cause mismatch between update and + ** paint rountines. Ignore paint request when invalid parameter + ** causes crash. + */ + if( screen_y > 400 ){ + assert1( NO, "VDM: med gfx big rejected y=%d\n", screen_y ); + return; + } + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* Clip to window */ + height = 1; + if (len > 80) + len = 80; + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + inc = offset & 1 ? 3 : 1; + intelmem_ptr = get_screen_ptr(offset); + graph_ptr = (ULONG *) ((UTINY *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y * bytes_per_scanline + screen_x)); + local_len = len; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = + cga_med_graph_hi_lut_big[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = + cga_med_graph_mid_lut_big[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = + cga_med_graph_lo_lut_big[*intelmem_ptr]; + graph_ptr++; + + intelmem_ptr += inc; + inc ^= 2; + } + while( --local_len ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(len << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*: Paints CGA medium res graphics for a colour monitor, in a huge window. :*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_med_graph_huge(int offset, int screen_x, int screen_y, + int len, int height) +{ +#ifdef BIGWIN + UTINY *intelmem_ptr; + ULONG *graph_ptr; + LONG local_len, + bytes_per_scanline, + longs_per_scanline; + ULONG inc; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_med_graph_huge off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + + /* + ** Tim Jan 93, rapid mode changes cause mismatch between update and + ** paint rountines. Ignore paint request when invalid parameter + ** causes crash. + */ + if( screen_y > 400 ){ + assert1( NO, "VDM: med gfx huge rejected y=%d\n", screen_y ); + return; + } + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* Clip to window */ + height = 1; + if (len > 80) + len = 80; + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + inc = offset & 1 ? 3 : 1; + intelmem_ptr = get_screen_ptr(offset); + graph_ptr = (ULONG *) ((UTINY *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y * bytes_per_scanline + screen_x)); + local_len = len; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + *(graph_ptr + 3 * longs_per_scanline) = + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = cga_med_graph_lut4_huge[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + 3 * longs_per_scanline) = + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = cga_med_graph_lut3_huge[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + 3 * longs_per_scanline) = + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = cga_med_graph_lut2_huge[*intelmem_ptr]; + graph_ptr++; + + *(graph_ptr + 3 * longs_per_scanline) = + *(graph_ptr + 2 * longs_per_scanline) = + *(graph_ptr + longs_per_scanline) = + *graph_ptr = cga_med_graph_lut1_huge[*intelmem_ptr]; + graph_ptr++; + + intelmem_ptr += inc; + inc ^= 2; + } + while(--local_len); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(len << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*: Paints CGA high res graphics for a colour monitor, in a standard window */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_hi_graph_std(int offset, int screen_x, int screen_y, + int len, int height) +{ + register char *intelmem, + *bufptr; + register int i; + int bytes_per_scanline; + SMALL_RECT rect; + static int rejections=0; /* Stop floods of rejected messages */ + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_hi_graph_std off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + if( rejections == 0 ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + rejections = 1; + } + return; + }else + rejections=0; + + /* Clip to window */ + height = 1; + if (len > 80) + len = 80; + + /* Work out offset, in bytes, of pixel directly below current pixel. */ + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* + * Build up DIB data. In 200-line CGA mode, pixels are double height so + * one line of PC pixels is equivalent to two lines of host pixels. + * Note: `height' parameter is always 1 when this function is called so + * only 1 line at a time is updated. + */ + intelmem = (char *) get_screen_ptr(offset); + + bufptr = (char *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bytes_per_scanline + + (screen_x >> 3); + for( i = len; i > 0; i-- ) + { + *(bufptr + bytes_per_scanline) = *bufptr = *intelmem; + intelmem += CGA_GRAPH_INCVAL; + bufptr++; + } + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (len << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paints CGA high res graphics for a colour monitor, in a big window :::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_hi_graph_big(int offset, int screen_x, int screen_y, + int len, int height) +{ +#ifdef BIGWIN + register char *intelmem, + *bufptr; + register int i; + char *buffer; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_hi_graph_big off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* Clip to window */ + height = 1; + if (len > 80) + len = 80; + + /* + * In this mode each byte becomes 12 bits (1.5 screen size) so if screen_x + * is on an odd byte boundary the resulting bitmap starts on a half-byte + * boundary. To avoid this set screen_x to the previous even byte. + */ + if (screen_x & 8) + { + screen_x -= 8; + offset -= CGA_GRAPH_INCVAL; + len++; + } + + /* `len' must be even for `high_stretch3' to work. */ + if (len & 1) + len++; + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + bufptr = buffer = (char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y * bytes_per_scanline + (screen_x >> 3)); + intelmem = (char *) get_screen_ptr(offset); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + for(i = len; i > 0; i--) + { + *bufptr = *intelmem; + intelmem += CGA_GRAPH_INCVAL; + bufptr++; + } + + high_stretch3((unsigned char *) buffer, len); + + memcpy(buffer + bytes_per_scanline, buffer, SCALE(len)); + memcpy(buffer + 2 * bytes_per_scanline, buffer, SCALE(len)); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(len << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paints CGA high res graphics for a colour monitor, in a huge window ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_colour_hi_graph_huge(int offset, int screen_x, int screen_y, + int len, int height ) +{ +#ifdef BIGWIN + register char *intelmem, + *bufptr; + char *buffer; + register int i; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_colour_hi_graph_huge off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* Clip to window */ + height = 1; + if (len > 80) + len = 80; + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + intelmem = (char *) get_screen_ptr(offset); + bufptr = buffer = (char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y * bytes_per_scanline + (screen_x >> 3)); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + for( i = len; i > 0; i-- ) + { + *bufptr = *intelmem; + intelmem += CGA_GRAPH_INCVAL; + bufptr++; + } + + high_stretch4((unsigned char *) buffer, len); + + memcpy(buffer + bytes_per_scanline, buffer, SCALE(len)); + memcpy(buffer + 2 * bytes_per_scanline, buffer, SCALE(len)); + memcpy(buffer + 3 * bytes_per_scanline, buffer, SCALE(len)); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(len << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +#ifdef MONITOR +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Paints CGA medium res graphics frozen window. */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_med_frozen_std(int offset, int screen_x, int screen_y, int len, + int height) +{ + UTINY *plane1_ptr, + *plane2_ptr, + data; + ULONG *graph_ptr, + longs_per_scanline, + local_len, + mem_x = screen_x >> 3, + mem_y = screen_y >> 1, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height >> 1; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_med_frozen_std off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((mem_x >= max_width) || (mem_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_cga_med_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (mem_x + len > max_width) + len = max_width - mem_x; + if (mem_y + height > max_height) + height = max_height - mem_y; + + /* Work out the width of a line (ie 640 pixels) in ints. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + + /* memory in this routine liable to be removed by fullscreen switch */ + try + { + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Set up data pointers. */ + graph_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + screen_y * longs_per_scanline + (screen_x >> 2); + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + + /* Each iteration of the loop processes 2 host bytes. */ + local_len = len >> 1; + + /* 'offset' is designed for interleaved planes. */ + offset >>= 1; + + /* 'height' is always 1 so copy a line to the bitmap. */ + do + { + data = *(plane1_ptr + offset); + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_hi_nyb[data]; + graph_ptr++; + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_lo_nyb[data]; + graph_ptr++; + data = *(plane2_ptr + offset); + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_hi_nyb[data]; + graph_ptr++; + *(graph_ptr + longs_per_scanline) = *graph_ptr = + cga_med_graph_lo_nyb[data]; + graph_ptr++; + offset += 2; + } + while (--local_len); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (len << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + { + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_cga_med_frozen_std. fs switch?"); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Paints CGA high res graphics frozen window. */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_cga_hi_frozen_std(int offset, int screen_x, int screen_y, int len, + int height) +{ + UTINY *plane1_ptr, + *graph_ptr; + ULONG bytes_per_scanline, + local_len, + mem_x = screen_x >> 3, + mem_y = screen_y >> 1, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height >> 1; + SMALL_RECT rect; + + sub_note_trace5(CGA_HOST_VERBOSE, + "nt_cga_hi_frozen_std off=%d x=%d y=%d len=%d height=%d\n", + offset, screen_x, screen_y, len, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((mem_x >= max_width) || (mem_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_cga_hi_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (mem_x + len > max_width) + len = max_width - mem_x; + if (mem_y + height > max_height) + height = max_height - mem_y; + + /* memory here liable to be removed by fullscreen switch */ + try + { + /* Work out the width of a line (ie 640 pixels) in ints. */ + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + + /* 'offset' is designed for interleaved planes. */ + offset >>= 2; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Set up data pointers. */ + graph_ptr = (UTINY *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bytes_per_scanline + screen_x; + plane1_ptr = GET_OFFSET(Plane1Offset) + offset; + + /* 'height' is always 1 so copy a line to the bitmap. */ + local_len = len; + do + { + *(graph_ptr + bytes_per_scanline) = *graph_ptr = *plane1_ptr++; + graph_ptr++; + } + while (--local_len); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (len << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + { + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_ega_hi_frozen_std. fs switch?"); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Dummy paint routine for frozen screens. ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_dummy_frozen(int offset, int screen_x, int screen_y, int len, + int height) +{ + assert0(NO, "Frozen screen error - dummy paint routine called."); +} +#endif /* MONITOR */ diff --git a/private/mvdm/softpc.new/host/src/nt_com.c b/private/mvdm/softpc.new/host/src/nt_com.c new file mode 100644 index 000000000..4900c27ca --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_com.c @@ -0,0 +1,2206 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntddser.h> +#include <windows.h> +#include <vdm.h> +#include "ptypes32.h" +#include "insignia.h" +#include "host_def.h" + +/* + * Ade Brownlow + * Wed Jul 10 91 + * + * nt_com.c + * + * + */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#include "xt.h" +#include "rs232.h" +#include "error.h" +#include "config.h" +#include "ica.h" +#include "ios.h" +#include "host_com.h" +#include "host_trc.h" +#include "debug.h" +#include "idetect.h" +#include "nt_com.h" + +#include <math.h> +#include <malloc.h> +#include <stdlib.h> +#include <stdio.h> +#include <excpt.h> +#include <nt_timer.h> +#include <nt_eoi.h> + + +/*:::::::::::::::::::::::::::::::::::::::::::::: Standard host com interface */ + +GLOBAL void host_com_init(int); +GLOBAL CPU void host_com_close IPT1(int, adapter); +GLOBAL RXCPU VOID host_com_read IPT3(int, adapter, UTINY *, data, int *, error); +GLOBAL RXCPU void host_com_write IPT2(int, adapter, char, data); +GLOBAL void host_com_ioctl(int, int, long); +GLOBAL void host_com_reset(int); + +GLOBAL void host_com_lock(int adapter); +GLOBAL void host_com_unlock(int adapter); +GLOBAL int host_com_open(int); + +#if 0 +GLOBAL boolean host_com_suspend(int adapter); +GLOBAL boolean host_com_resume(int adapter); +#endif + +/* autoflush stub */ +GLOBAL void host_setup_aflush (int); +GLOBAL DWORD nt_poll_comms(DWORD); +DWORD PollCommsThread(PVOID pv); + +/*:::::::::::::::::::::::::::::: TX flush and control functions and defines */ + +#define TX_MAX_BUFFER (200) +#define TX_SCALING_TRIGGER (2) + +typedef enum { XOFF_TRIGGER, TIMER_TRIGGER, TXFULL_TRIGGER, CLOSE_TRIGGER } FLUSHTYPE; + +/*::::::::::::::::::::::::::::::::::::::::: Local adaptor control structure */ + +#define MAX_PENDING_WRITES (3) +// this is the buffer size we ask the serial driver to allocate +// for its isr buffer(nopaged pool with quota). TonyE said it is no harm +// to give it a bigger one(a big smile, eh). 4KB already gave us lots +// of trouble, especially, on a slow machine. +#define INPUT_QUEUE_SIZE (8*1024) +#define OUTPUT_QUEUE_SIZE 100 + +// this is the buffer size we use to receive rx data from serial driver +// it should be big enough to prevent the serial driver from overflowing its +// ISR buffer. The speed we delivery rx data to the application can not +// keep up with the speed that serial driver can handle. + +#define BUFFER_SIZE INPUT_QUEUE_SIZE *2 + + +// this is the max number of chars we delivery to the application +// before the CPU thread gives the RX thread a taste of CPU. +// Too small, we waste too much time doing context switching and deliverying +// too many unnecessary rda interrupts to some smart application ISR, +// thus, reduce the overall throughput. Too big, we choke the application +// (because we immediately delivery another rda interrupt to the +// application as soon as the application IRET). +// Application RX buffer size can be anywhere and depends how smart the +// appllication ISR is, we may make the application really angry. +// Some application ISR read LSR register after it gets the first char +// and if the LSR indicates that there is another bytes ready, +// it reads it immediately without waiting for the other int. +// Some application set the IER after EOI an RDA int and expects +// another interrupt. +#define DEFAULT_RXWINDOW_SIZE 256 + + +#define ADAPTER_NULL 0 /* NULL device (/dev/null) */ +#define ADAPTER_REAL 1 /* Real comm port device */ +#define ADAPTER_SUSPENDED 2 /* Real device suspended */ + +typedef struct _COM_STATES { + UCHAR Break; + UCHAR DTR; + UCHAR RTS; + UCHAR Parity; + UCHAR StopBits; + UCHAR DataBits; + DWORD BaudRate; +}COM_STATES, *PCOM_STATES; + + +#define ESCAPECHAR ((UCHAR)(-1)) +typedef struct _host_com +{ + HANDLE handle; /* Device handle */ + int type; /* hopefully NULL or a device */ + BOOL rx; + BOOL dcbValid; /* TRUE if dcbBeforeOpen contains a valid DCB */ + DCB dcbBeforeOpen; /* device control block before open*/ + DWORD modem_status; /* modem status line settings */ + HANDLE ModemEvent; /* Get modem status control event */ + + int controller; /* ICA control used */ + int line; /* ICA line */ + + /*..................................... Error display control variables */ + + BOOL DisplayError; /* Enabled/Disabled */ + + /*......................................... RX buffer control variables */ + UCHAR * buffer; /* rx buffer */ + int head_inx; /* Next place to add char to */ + int tail_inx; /* Next place to remove char from */ + int bytes_in_rxbuf; /* Number of bytes in buffer */ + int rxwindow_size; /* rx buffer sliding window size */ + int bytes_in_rxwindow; /* bytes in the rx window */ + int EscapeCount; + int EscapeType; + + BOOL CharReadFromUART; + int RXFlushTrigger; + + HANDLE RXControlObject; + DWORD SignalRXThread; + + /*......................................... TX buffer control variables */ + + unsigned char TXBuffer[TX_MAX_BUFFER]; + int no_tx_chars; /* Chars in tx buffer */ + int tx_threshold; /* Current flush threshold */ + int max_tx_threshold; /* Max flush threshold */ + + int tx_flush_count; /* No. of flushs of below size */ + int tx_heart_beat_count; + int tx_timer_flush_count; /* Consecutive timer flush counts */ + int todate_timer_flush_total; + + OVERLAPPED DWOV[MAX_PENDING_WRITES];/* Delayed writes */ + int DWOVInx; /* Delayed writes index */ + + /*.............................................. Access control objects */ + + CRITICAL_SECTION CSEvent; /* Used to control access to above */ + CRITICAL_SECTION AdapterLock; + int AdapterLockCnt; /* Adapter lock count */ + + volatile BOOL TerminateRXThread; + + int ReOpenCounter; /* Counter to prevent to many open attempts */ + int RX_in_Control; + + /*.......................................... XON/XOFF control variables */ + + HANDLE XOFFEvent; /* XOFF ioctl competion event */ + BOOL XOFFInProgress; /* XOFF currently in progress */ + + void *firstStatusBlock; /* first block in IO status block linked list */ + void *lastStatusBlock; /* last block in IO staus block linked list */ + + /*...................................... Overlapped I/O control handles */ + + HANDLE RXEvent; /* Overlapped read complete event */ + HANDLE TXEvent[MAX_PENDING_WRITES]; /* Overlapped write complete event */ + + HANDLE EvtHandle; /* Used by WaitCommEvent */ + + /*............................................. RX thread handle and ID */ + + DWORD RXThreadID; /* RX thread ID */ + HANDLE RXThreadHandle; /* RX thread handle */ + COM_STATES ComStates; /* Com device states as we know it */ + int SuspendTimeoutTicks; /* auto close ticks setting */ + int SuspendTickCounter; /* auto close tick counter */ + BOOL SyncWrite; /* TRUE if we should write data synchrounously */ + BOOL Suspended; /* TRUE if the port has been suspended */ + BOOL Suspending; /* TRUE when the port is being suspended */ + DWORD TickCount; + +} HOST_COM, *PHOST_COM; + +#define BUMP_TAIL_INX(t,c) (c)--;if(++(t) == BUFFER_SIZE) (t) = 0; + +typedef enum { RXCHAR, CHARINERROR, RXERROR, MODEMSTATE, RXBUFEMPTY, UNKNOWN} RXBUFCHARTYPE; + +/*:::::::::::::::::::::::::::::::::::::::::::::::::: Local function protocols */ + +DWORD GetCharsFromDriver(int adaptor); +void RX GetErrorFromDriver(int adapter); +CPU int SendXOFFIoctlToDriver(int adapter); + +DWORD ReadWaitTimeOut(int adapter); +int MapHostToBaseError(UCHAR host_error); + +void RX WaitForAllXOFFsToComplete(int adapter); +BOOL RX RemoveCompletedXOFFs(int adapter); +void SendDataToDriver(int adatper, char data); + +void CPU FlushTXBuffer(int adapter, FLUSHTYPE FlushReason); +void ScaleTXThreshold(register HOST_COM *current, FLUSHTYPE FlushReason); + +GLOBAL void host_com_EOI_hook(long adapter); +GLOBAL void CPU host_com_poll(int adapter); + +RXBUFCHARTYPE GetCharacterTypeInBuffer(register HOST_COM *current); +void CPU EmptyRXBuffer(int adapter); +void GetCharFromRXBuffer(HOST_COM *current, RXBUFCHARTYPE type, + UCHAR *data, UCHAR *error); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: LOCAL DATA */ + +LOCAL HOST_COM host_com[4]; /* 4 comm ports - the insignia MAX */ + +LOCAL PHOST_COM host_com_ptr[4] = { &host_com[0], &host_com[1],&host_com[2], + &host_com[3]}; + +LOCAL int disable_open[4] = { FALSE, FALSE, FALSE, FALSE }; + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Local defines */ + +#define CURRENT_ADAPTER() register HOST_COM *current = host_com_ptr[adapter] + +#define EV_MODEM (EV_CTS | EV_DSR | EV_RING | EV_RLSD) +//#define EV_MODEM (EV_DSR | EV_RING | EV_RLSD) + +#define XON_CHARACTER (17) /* XON character, Cntrl-Q */ +#define XOFF_CHARACTER (19) /* XOFF character, Cntrl-S */ +#define XOFF_TIMEOUT (2*1000) /* Timeout in milliseconds */ +#define XOFF_RXCHARCNT (5) /* RX character count */ + +#define REOPEN_DELAY (36) /* Reopen delay in 55ms (2 secs) */ +#define RXFLUSHTRIGGER (36) /* RX flush trigger (2 secs), if a + character is not read from the + UART within this time the RX buffer + is flushed */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Init comms system ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#include "error.h" +#include "host_rrr.h" +#include "nt_uis.h" + + +GLOBAL CPU void host_com_init IFN1(int, adapter) +{ + UNUSED(adapter); + + // Comms ports are only opened when they are accessed. +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Disable Open :::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +//This is called at the start of the adapter init code to prevent the comm +//port being opened during com_init() + +void host_com_disable_open IFN2(int, adapter, int, DisableOpen) +{ + disable_open[adapter] = DisableOpen; +} + + +#ifdef NTVDM +boolean host_com_check_adapter(int adapter) +{ + CURRENT_ADAPTER(); + return (current->type == ADAPTER_REAL); + +} +#endif + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Open comms port ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Called first time port is written to ! */ + +GLOBAL CPU int host_com_open(int adapter) +{ + COMMTIMEOUTS comout; /* Comm port time out settings */ + DIVISOR_LATCH divisor_latch; /* Current latch settings */ + LINE_CONTROL_REG LCR_reg; /* Current LCR status */ + int i; + DCB LocalDCB; + ConfigValues ComConfigValues; + + CURRENT_ADAPTER(); /* Define and setup pointer to adapter */ + + /*:::::::::::::::::::::::::::::::::::::::::: Is the port already open ? */ + + if(current->type == ADAPTER_REAL) + return(TRUE); /* Exit port already open */ + + /*::::::::::: Attempting to open the port to soon after a failed open ? */ + + if(current->ReOpenCounter || disable_open[adapter]) + return(FALSE); /* Yes */ + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + always_trace1("HOST_COM_OPEN adapter= %d\n", adapter); + + /*::::::::::::::::::::::::::::::::::::::::::::: Check for a NULL device */ + + if(adapter > 3 || adapter < 0) + { + current->type = ADAPTER_NULL; + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); /* Open attempt failed */ + } + + /*::::::::::::::::::::::::::: We have a vaild adapter so try to open it */ + config_inquire((UTINY)(C_COM1_NAME + adapter), + &ComConfigValues); + current->handle = CreateFile(ComConfigValues.string, + GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + /*............................................... Validate open attempt */ + + if(current->handle == (HANDLE) -1) + { + always_trace1("Cannot open comms port '%s'\n", + (CHAR*) config_inquire((UTINY)(C_COM1_NAME+adapter),NULL)); + + if(current->DisplayError) { + RcErrorBoxPrintf(EHS_ERR_OPENING_COM_PORT, + (CHAR*) config_inquire((UTINY)(C_COM1_NAME+adapter),NULL)); + current->DisplayError = FALSE; //Error only display once per session + } + + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + current->type = ADAPTER_NULL; /* Unable to open adapter */ + return(FALSE); + } + + + /* allocate rx buffer and initialize rx queue size */ + + current->buffer = (UCHAR *) malloc(BUFFER_SIZE); + if (current->buffer == NULL) { + CloseHandle(current->handle); + current->type = ADAPTER_NULL; + return FALSE; + } + current->rxwindow_size = DEFAULT_RXWINDOW_SIZE; + current->bytes_in_rxwindow = 0; + current->SyncWrite = (BOOL)config_inquire(C_COM_SYNCWRITE, NULL); + /*:: Find out which ICA controller and line are used by this comms port */ + + com_int_data(adapter, ¤t->controller, ¤t->line); + + /*::::::::::::::::::::::::::::::: Enable IRET hooks for comms interrupt */ + +#ifdef MONITOR + ica_iret_hook_control(current->controller, current->line, TRUE); +#endif + + /*:::::::::::::::::::::: Create objects used to control comms activity */ + + current->ModemEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->RXControlObject = CreateEvent(NULL,FALSE,FALSE,NULL); + current->RXEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->EvtHandle = CreateEvent(NULL,TRUE,FALSE,NULL); + current->DWOVInx = 0; + + //Create objects used to control multipe overlapping writes + for(i=0; i < MAX_PENDING_WRITES; i++) + { + //Objects must be created in the signalled state for the closedown + //routine to function correctly + + current->TXEvent[i] = CreateEvent(NULL,TRUE,TRUE,NULL); + current->DWOV[i].hEvent = NULL; + } + + /*::::::::::::::::::::::::::::::::::::::::::::::::: Empty RX/TX buffers */ + + current->head_inx = current->tail_inx = 0; + current->EscapeCount = current->bytes_in_rxbuf = current->no_tx_chars = 0; + + current->CharReadFromUART = FALSE; + current->RXFlushTrigger = RXFLUSHTRIGGER; + current->RX_in_Control = TRUE; + current->SignalRXThread = (DWORD) 0; + /*:::::::::::::::::::::::::::::::::::::::::::: Get TX buffer thresholds */ + + current->max_tx_threshold = (short)config_inquire(C_COM_TXBUFFER_SIZE, NULL); + if (!current->max_tx_threshold || current->max_tx_threshold > TX_MAX_BUFFER) + current->max_tx_threshold = TX_MAX_BUFFER; + + //Setup other delayed write control variables + if (current->max_tx_threshold == 1) + current->tx_threshold = 0; + current->tx_flush_count = 0; // No. of flushs of below size + /*::::::::::::::::::::::::::: Extended control variables used by adaper */ + + current->type = ADAPTER_REAL; /* Adapter type */ + current->TerminateRXThread = FALSE; /* RX thread termination flag */ + + /*:::::::::::::::::::::::::::::::: Initialise the XOFF control varibles */ + + current->XOFFInProgress = FALSE; + current->XOFFEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->firstStatusBlock = current->lastStatusBlock = NULL; + + /*:::: Init critical sections used to sync access to host functions, data */ + + /* critical section used to control access to adapters data structure */ + InitializeCriticalSection(¤t->CSEvent); + + /* critical section used to lock access to adapter from the base */ + InitializeCriticalSection(¤t->AdapterLock); + current->AdapterLockCnt = 0; + + /* NULL thread handle because host_com_close() may be called before + the comms RX thread is created */ + + current->RXThreadHandle = NULL; + current->dcbValid = FALSE; + /*::::::::::::::::::::::::::::::::::::::: Set Comms port to binary mode */ + + if(!GetCommState(current->handle, &(current->dcbBeforeOpen))) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + host_com_close(adapter); /* turn it into a NULL adapter */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + current->dcbValid = TRUE; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Setup DCB */ + + + /* we make a local copy of DCB because we have to reset the DCB + * to whatever it was before we opened it. This function is the only place + * we ever touch DCB. + */ + + LocalDCB = current->dcbBeforeOpen; + LocalDCB.fBinary = 1; /* Run in RAW mode */ + LocalDCB.fOutxCtsFlow = FALSE; /* Disable CTS */ + LocalDCB.fOutxDsrFlow = FALSE; /* Disable DSR */ + LocalDCB.fDtrControl = DTR_CONTROL_DISABLE; + LocalDCB.fOutX = FALSE; /* Disable XON/XOFF */ + LocalDCB.fInX = FALSE; + LocalDCB.fRtsControl = RTS_CONTROL_DISABLE; + + LocalDCB.XonChar = XON_CHARACTER; /* Define XON/XOFF chars */ + LocalDCB.XoffChar = XOFF_CHARACTER; + LocalDCB.fErrorChar = FALSE; /* Turn off error char replacement */ + /* if we are resuming the device, initialize DCB parameters to + * what they were before suspended + */ + if (current->Suspended) { + LocalDCB.BaudRate = current->ComStates.BaudRate; + LocalDCB.Parity = current->ComStates.Parity; + LocalDCB.StopBits = current->ComStates.StopBits; + LocalDCB.ByteSize = current->ComStates.DataBits; + LocalDCB.fParity = (LocalDCB.Parity == NOPARITY); + } + /* initialize the ComStates by copying data from DCB */ + else { + current->ComStates.BaudRate = current->dcbBeforeOpen.BaudRate; + current->ComStates.Parity = current->dcbBeforeOpen.Parity; + current->ComStates.StopBits = current->dcbBeforeOpen.StopBits; + current->ComStates.DataBits = current->dcbBeforeOpen.ByteSize; + current->ComStates.Break = 0; + } + ASSERT(LocalDCB.BaudRate != 0); + + /*::::::::::::::::::::::::::::::::::: Sync base to current line settings */ + + if(!SyncLineSettings(NULL, &(LocalDCB), &divisor_latch, &LCR_reg)) + { + always_trace0("ntvdm : Unable to sync line states\n"); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + SyncBaseLineSettings(adapter,&divisor_latch, &LCR_reg); + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Set Comms port state */ + + if(!SetCommState(current->handle, &(LocalDCB))) + { + always_trace0("ntvdm : SetCommState failed on open\n"); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::: Put the driver into streaming MSR,LSR, RX mode */ + + if(!EnableMSRLSRRXmode(current->handle, current->ModemEvent, + (unsigned char) ESCAPECHAR)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + host_com_close(adapter); /* turn it into a NULL adapter */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::::::::::::::::::::::: Setup comm port queue sizes */ + + if(!SetupComm(current->handle,INPUT_QUEUE_SIZE,OUTPUT_QUEUE_SIZE)) + { + always_trace1("ntvdm : SetupComm failed, %d\n",GetLastError()); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::: Set communication port up for non-blocking read */ + + GetCommTimeouts(current->handle,&comout); + + comout.ReadIntervalTimeout = (DWORD) -1; + comout.ReadTotalTimeoutMultiplier = 0; + comout.ReadTotalTimeoutConstant = 0; + + SetCommTimeouts(current->handle,&comout); + + /* restore device states in case of resume */ + if (current->Suspended) { + /* break line */ + if (current->ComStates.Break) + SetCommBreak(current->handle); + else + ClearCommBreak(current->handle); + /* Data Terminal Ready line */ + if (current->ComStates.DTR) + EscapeCommFunction(current->handle, SETDTR); + else + EscapeCommFunction(current->handle, CLRDTR); + /* Request To Send line */ + if (current->ComStates.RTS) + EscapeCommFunction(current->handle, SETRTS); + else + EscapeCommFunction(current->handle, CLRRTS); + + /* parity, stop bits and data bits */ + FastCommSetLineControl(current->handle, + current->ComStates.StopBits, + current->ComStates.Parity, + current->ComStates.DataBits + ); + /* baud rate */ + FastCommSetBaudRate(current->handle, current->ComStates.BaudRate); + + /* we are no longer in suspended state */ + current->Suspended = FALSE; + + } + else { + /*::::::::::::::::::::::::::::::::::::::::::::: Setup RTS and DTR states */ + setup_RTSDTR(adapter); + } + + /*::::::::::::::::::::::::::::::::::::::::::::::: Create Comms RX thread */ + + if(!(current->RXThreadHandle = CreateThread(NULL, + 8192, + PollCommsThread, + (LPVOID)adapter, + 0, + ¤t->RXThreadID))) + { + always_trace1("ntvdm : Failed comms thread for %d\n", adapter); + host_com_close(adapter); /* Unable to create RX thread */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + /* reset the counter */ + current->SuspendTimeoutTicks = ComConfigValues.index * 1000; + current->SuspendTickCounter = current->SuspendTimeoutTicks; + current->TickCount = 0; + return(TRUE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Close all open comms ports :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL CPU void host_com_close_all(void) +{ + int adapter; + + for(adapter = 0; adapter < 4; adapter++) + { + host_com[adapter].DisplayError = TRUE; //Enable error displaying + host_com_close(adapter); + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Close comms port ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL CPU void host_com_close IFN1(int, adapter) +{ + CURRENT_ADAPTER(); + int i; + + /*:::::::::::::::::::::::::::::::::::::::: Dealing with NULL adapter ? */ + + if(current->type != ADAPTER_NULL) + { + always_trace1("Closing comms port %d\n",adapter); + + /* only touch the device if we own the device */ + if (current->type == ADAPTER_REAL) { + /*....... Flush any delayed writes and wait for writes to complete */ + if (current->no_tx_chars) + FlushTXBuffer(adapter,CLOSE_TRIGGER); + WaitForMultipleObjects(MAX_PENDING_WRITES,current->TXEvent,TRUE,INFINITE); + /* reset DCB to whatever it was before open */ + if (current->dcbValid) { + SetCommState(current->handle, ¤t->dcbBeforeOpen); + current->dcbValid = FALSE; + } + + } + + + /* keep the base adapter states intact if we are suspending the device */ + if (!current->Suspending) + /*........................................ Reset base comms adatper */ + com_init(adapter); /* Initialise base comms adapter */ + + /*................................................. Close RX thread */ + + if(current->RXThreadHandle) + { + /*................................. Tell RX thread to terminate */ + + current->TerminateRXThread = TRUE; // Tell RX thread to terminate + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + + /* Wait for RX thread to close itself, max wait 30 seconds */ + + WaitForSingleObject(current->RXThreadHandle,30000); + CloseHandle(current->RXThreadHandle); + + current->RXThreadHandle = NULL; // Mark thread as closed + } + /* now it is safe to close the device */ + CloseHandle(current->handle); current->handle = NULL; + + /*............... Delete RX critical section and RX control objects */ + + DeleteCriticalSection(¤t->CSEvent); + DeleteCriticalSection(¤t->AdapterLock); + + /*............................................. Close event objects */ + + CloseHandle(current->ModemEvent); + CloseHandle(current->RXControlObject); + CloseHandle(current->RXEvent); // Overlapped read wait object + for(i=0; i < MAX_PENDING_WRITES; i++) + { + CloseHandle(current->TXEvent[i]); // Overlapped write wait object + current->TXEvent[i] = NULL; + } + + CloseHandle(current->EvtHandle); // WaitCommEvent wait object + CloseHandle(current->XOFFEvent); + + current->XOFFEvent = current->RXEvent = current->EvtHandle = NULL; + + /*.......................... Disable IRET hooks for comms interrupt */ + +#ifdef MONITOR + ica_iret_hook_control(current->controller, current->line, FALSE); +#endif + + /*. This makes sure that the next access to the port will reopen it */ + current->ReOpenCounter = 0; + + free(current->buffer); + current->buffer = NULL; + current->type = ADAPTER_NULL; /* Mark adapter as closed */ + } + else if (current->Suspended) { + /* the application is terminating while the port is suspended. + * first we turn the disable-open on so that we will not try + * to physical touch the port. Then we call base to reset the + * adapter + */ + + BOOL DisableOpen; + DisableOpen = disable_open[adapter]; + disable_open[adapter] = TRUE; + com_init(adapter); + disable_open[adapter] = DisableOpen; + current->Suspended = FALSE; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Request from base for character :::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#ifdef FIFO_ON +GLOBAL CPU UTINY host_com_read_char( int adapter, FIFORXDATA * buffer, UTINY count) +{ + CURRENT_ADAPTER(); + UCHAR host_error; + RXBUFCHARTYPE CharType; + UTINY RetCount = count; + /* if xoff is in progress, don't read nothing */ + if (!current->XOFFInProgress) { + while (count) { + CharType = GetCharacterTypeInBuffer(current); + if (CharType == RXCHAR || CharType == CHARINERROR) { + buffer->error = 0; + GetCharFromRXBuffer(current, CharType, &buffer->data, &host_error); + if (!host_error) + buffer->error = MapHostToBaseError(host_error); + buffer++; + count--; + } + else + break; + } + } + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; + return (RetCount - count); + +} +GLOBAL CPU void host_com_fifo_char_read(int adapter) +{ + CURRENT_ADAPTER(); + current->CharReadFromUART = TRUE; +} +#endif + +GLOBAL RXCPU VOID host_com_read IFN3(int, adapter, UTINY *, data, int *, error) +{ + CURRENT_ADAPTER(); + UCHAR host_error; + RXBUFCHARTYPE CharType; + BOOL MoreToProcess = TRUE; + /*::::::::::::::::::::::::::::::::::::::::: Dealing with NULL adapter ? */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + /*::::::::::::::::::::::: Get next character from input character queue */ + + + while(MoreToProcess) + { + + CharType = GetCharacterTypeInBuffer(current); + + //Process next character in buffer + switch(CharType) + { + //................................................Process character + + case RXCHAR: + case CHARINERROR: + host_error = 0; + GetCharFromRXBuffer(current,CharType,(UCHAR *)data,&host_error); + + //error reading character + if(host_error) + *error = MapHostToBaseError(host_error); /* Get error */ + MoreToProcess = FALSE; + break; + + //.....................Process receive error, no character available + + case RXERROR: + com_lsr_change(adapter); + break; + + //...................................... Process modem state changes + + case MODEMSTATE: + com_modem_change(adapter); + break; + + //..................................................RX buffer empty + + case RXBUFEMPTY: + always_trace0("Read requested on empty RX buffer"); + *error = 0; *data = (UTINY)-1; //Buffer empty + MoreToProcess = FALSE; + break; + + case UNKNOWN: + GetCharFromRXBuffer(current,CharType,(UCHAR *)data,&host_error); + *error = MapHostToBaseError(host_error); /* Get error */ + MoreToProcess = FALSE; + break; + + } + } + + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; +} + +/*:::::::::::::::::::::::::: Comms read returned to application by the base */ +// This function is called after each character is read from the comms port + +int CPU host_com_char_read(int adapter, int data_available_ints) +{ + CURRENT_ADAPTER(); + + current->CharReadFromUART = TRUE; //Char read from UART + if(data_available_ints) + host_com_EOI_hook((long) adapter); + else + host_com_poll(adapter); + + return(0); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Map host error to base error ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int RXCPU MapHostToBaseError(UCHAR host_error) +{ + int base_error = 0; + LINE_STATUS_REG LSR; + + LSR.all = host_error; + if(LSR.bits.framing_error) base_error |= HOST_COM_FRAMING_ERROR; + if(LSR.bits.parity_error) base_error |= HOST_COM_PARITY_ERROR; + if(LSR.bits.break_interrupt) base_error |= HOST_COM_BREAK_RECEIVED; + if(LSR.bits.overrun_error) base_error |= HOST_COM_OVERRUN_ERROR; + + return(base_error); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Write to comms port :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL RXCPU void host_com_write IFN2(int, adapter, char, data) +{ + CURRENT_ADAPTER(); + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a NULL adapter */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + if(data == XOFF_CHARACTER || data == XON_CHARACTER) + sub_note_trace1(HOST_COM_VERBOSE,"XO%s sent",data == XOFF_CHARACTER ? "FF" : "N"); + + /*::::::::::::::::::::::::::::::::::::::::: Is the user sending an XOFF */ + + + if(data == XOFF_CHARACTER) + { + if(current->no_tx_chars) FlushTXBuffer(adapter,XOFF_TRIGGER); + SendXOFFIoctlToDriver(adapter); + } + else + SendDataToDriver(adapter,data); + + /*::::::::::: Tell comms idle system that there has been comms activity */ + + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; + /* tell base that the tx holding register is empty */ + tx_holding_register_empty(adapter); + /* async write mode -> tell base that the tx shift register is empty + * sync mode -> FlushTxBuffer will do the signaling. + */ + if (!current->SyncWrite) + tx_shift_register_empty(adapter); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::: Write data to driver */ + +void SendDataToDriver(int adapter, char data) +{ + DWORD BytesWritten, error = 0; + OVERLAPPED OV; + CURRENT_ADAPTER(); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Delay write ? */ + + if(current->tx_threshold) + { + //Add char to tx buffer queue + current->TXBuffer[current->no_tx_chars++] = (unsigned char) data; + + + //Write threshold reached ? + if(current->tx_threshold <= current->no_tx_chars || + current->XOFFInProgress) + FlushTXBuffer(adapter,(current->XOFFInProgress) ? + XOFF_TRIGGER : TXFULL_TRIGGER); + return; + } + + + /*:::::::::::::::::::::::::::::: Setup overlapped I/O control structure */ + + OV.hEvent = current->TXEvent[0]; /* Event used to signal completion */ + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Write character */ + + if(!WriteFile(current->handle, &data, 1, &BytesWritten, &OV)) + { + if((error = GetLastError()) == ERROR_IO_PENDING) + { + /* Write request pending wait for it to complete */ + if(GetOverlappedResult(current->handle,&OV,&BytesWritten,TRUE)) + error = 0; /* Write successful */ + else + error = GetLastError(); + } + + /* Reset comms port, clear error */ + if(error) ClearCommError(current->handle,&error,NULL); + } + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Display error */ + +#ifndef PROD + if(error) + always_trace2("host_com_write error, adapter %d,%d\n",adapter,error); +#endif + /* tell base that the tx shift register is empty */ + tx_shift_register_empty(adapter); + +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::: Send magic XOFF ioctl */ + +CPU int SendXOFFIoctlToDriver(int adapter) +{ + CURRENT_ADAPTER(); + void *newIOStatusBlock; + int rtn; + + /*.................... Allocate new IOstatus block, used by magic ioctl */ + + newIOStatusBlock = AllocStatusElement(); + + /*.............................................. Issue magic xoff IOCTL */ + + if(SendXOFFIoctl(current->handle, // Handle of comms port + current->XOFFEvent, // Event to signal completion on + XOFF_TIMEOUT, // Timeout in milliseconds + XOFF_RXCHARCNT, // RX character count + XOFF_CHARACTER, // XOFF character + newIOStatusBlock)) // IO status block for ioctl + + { + /*............................. Add new status block to linked list */ + + EnterCriticalSection(¤t->CSEvent); + + AddNewIOStatusBlockToList(¤t->firstStatusBlock, + ¤t->lastStatusBlock, newIOStatusBlock); + + current->XOFFInProgress = TRUE; + LeaveCriticalSection(¤t->CSEvent); + rtn =TRUE; // XOFF ioctl successful + } + else + { + /* Error, XOFF ioctl failed */ + free(newIOStatusBlock); + rtn = FALSE; // XOFF ioctl failed + } + + return(rtn); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +GLOBAL RXCPU void host_com_ioctl IFN3(int, adapter, int, request, long, arg) +{ + UCHAR host_modem, error; + MODEM_STATUS_REG MSR; + char BaudRateStr[100]; + ULONG ModemState; + UCHAR DataBits, StopBits, Parity; + + CURRENT_ADAPTER(); /* Define and set 'current' adaptor pointer */ + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL) + { + // Attempt to open adapter ! + + if(request == HOST_COM_FLUSH || request == HOST_COM_INPUT_READY || + request == HOST_COM_MODEM || !host_com_open(adapter)) + { + return; + } + } + /*:::::::::::::::::::::::::::::::::::::::::::::: Identify ioctl request */ + + + switch(request) + { + + case HOST_COM_LSR: + if(GetCharacterTypeInBuffer(current) == RXERROR) + { + GetCharFromRXBuffer(current, RXERROR, NULL, &error); + *(DWORD *)arg = (DWORD)error; + } + break; + + /*:::::::::::::::::::::::::::::::::::::::::: Process break requests */ + + case HOST_COM_SBRK: /* Set BREAK */ + sub_note_trace0(HOST_COM_VERBOSE, "set BREAK"); + SetCommBreak(current->handle); + current->ComStates.Break = 1; + break; + + case HOST_COM_CBRK: /* Clear BREAK */ + sub_note_trace0(HOST_COM_VERBOSE, "clear BREAK"); + ClearCommBreak(current->handle); + current->ComStates.Break = 0; + break; + + /*::::::::::::::::::::::::::::::::::::::::: Process baud rate change */ + + case HOST_COM_BAUD: + + if (!FastCommSetBaudRate(current->handle, arg)) + { + sprintf(BaudRateStr, "(%d)", arg); + host_error(EHS_UNSUPPORTED_BAUD, ERR_CONT, BaudRateStr); + always_trace1("set BAUD failed - SetBaudRate:%d", arg); + } + current->ComStates.BaudRate = (DWORD)arg; + + break; + + /*:::::::::::::::::::::::::::::::::::::::: Process DTR line requests */ + + case HOST_COM_SDTR: /* Set DTR line */ + //printf("Set DTR\n"); + sub_note_trace0(HOST_COM_VERBOSE, "set DTR"); + if(!EscapeCommFunction (current->handle, SETDTR)) + sub_note_trace0(HOST_COM_VERBOSE, "set DTR FAILED"); + current->ComStates.DTR = 1; + break; + + case HOST_COM_CDTR: /* Clear DTR line */ + //printf("Clear DTR\n"); + sub_note_trace0(HOST_COM_VERBOSE, "clear DTR"); + if(!EscapeCommFunction (current->handle, CLRDTR)) + sub_note_trace0(HOST_COM_VERBOSE, "clear DTR FAILED"); + current->ComStates.DTR = 0; + break; + + /*::::::::::::::::::::::::::::::::::::::::::::::::: flush comms port */ + + case HOST_COM_FLUSH: /* Flush comms port */ + sub_note_trace0(HOST_COM_VERBOSE, "Flush comms port"); + break; + + /*:::::::::::::::::::::::::::::::::::::::: Process RTS line requests */ + + case HOST_COM_CRTS: /* Clear RTS */ + //printf("Clear RTS\n"); + sub_note_trace0(HOST_COM_VERBOSE, "clear RTS"); + if(!EscapeCommFunction (current->handle, CLRRTS)) + sub_note_trace0(HOST_COM_VERBOSE, "clear RTS FAILED"); + current->ComStates.RTS = 0; + break; + + case HOST_COM_SRTS: + //printf("Set RTS\n"); + sub_note_trace0(HOST_COM_VERBOSE, "set RTS"); + if(!EscapeCommFunction (current->handle, SETRTS)) + sub_note_trace0(HOST_COM_VERBOSE, "set RTS FAILED"); + current->ComStates.RTS = 1; + break; + + /*::::::::::::::::::::::::::::::::::: Return status of the RX buffer */ + + case HOST_COM_INPUT_READY: + *(long *)arg = current->rx; /* check the port for data */ + break; + + /*:::::::::::::::::::::::::::::::::::::::::::::: Return modem status */ + + case HOST_COM_MODEM: /* Get modem state */ + + current->modem_status = 0; + if(GetCharacterTypeInBuffer(current) == MODEMSTATE) + { + GetCharFromRXBuffer(current, MODEMSTATE, &host_modem, &error); + MSR.all = host_modem; + + if(MSR.bits.CTS) current->modem_status |= HOST_COM_MODEM_CTS; + if(MSR.bits.RI) current->modem_status |= HOST_COM_MODEM_RI; + if(MSR.bits.DSR) current->modem_status |= HOST_COM_MODEM_DSR; + if(MSR.bits.RLSD) current->modem_status |= HOST_COM_MODEM_RLSD; + } + else + { + //.......................Get modem data from the serial driver ? + + FastGetCommModemStatus(current->handle, current->ModemEvent, + &ModemState); + + if(ModemState & MS_CTS_ON) + current->modem_status |= HOST_COM_MODEM_CTS; + + if(ModemState & MS_RING_ON) + current->modem_status |= HOST_COM_MODEM_RI; + + if(ModemState & MS_DSR_ON) + current->modem_status |= HOST_COM_MODEM_DSR; + + if(ModemState & MS_RLSD_ON) + current->modem_status |= HOST_COM_MODEM_RLSD; + } + + //.......................Return modem change information to the base + + sub_note_trace4(HOST_COM_VERBOSE, "CTS:%s RI:%s DSR:%s RLSD:%s", + current->modem_status & HOST_COM_MODEM_CTS ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_RI ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_DSR ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_RLSD ? "ON" : "OFF"); + + *(long *)arg = current->modem_status; + break; + + /*::::::::::::::::::::::::::::::::::::::::: Setup number of stop bits */ + + case HOST_COM_STOPBITS: + sub_note_trace1(HOST_COM_VERBOSE, "Setting Stop bits %d", arg); + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, + &DataBits)) + { + switch (arg) + { + case 1: + StopBits = ONESTOPBIT; + break; + case 2: + StopBits = DataBits == 5 ? ONE5STOPBITS : TWOSTOPBITS; + break; + + default: + always_trace1("STOPBITS strange request %d\n", arg); + break; + } + + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + + always_trace1("set STOPBITS failed- FastCommSetLineControl:%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.StopBits = StopBits; + break; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::::: Setup parity */ + + case HOST_COM_PARITY: + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, &DataBits)) + { + switch(arg) + { + case HOST_COM_PARITY_EVEN: + sub_note_trace0(HOST_COM_VERBOSE, "Set EVEN Parity"); + Parity=EVENPARITY; + break; + + case HOST_COM_PARITY_ODD: + sub_note_trace0(HOST_COM_VERBOSE, "Set ODD Parity"); + Parity=ODDPARITY; + break; + + case HOST_COM_PARITY_MARK: + sub_note_trace0(HOST_COM_VERBOSE, "Set MARK Parity"); + Parity=MARKPARITY; + break; + + case HOST_COM_PARITY_SPACE: + sub_note_trace0(HOST_COM_VERBOSE, "Set SPACE Parity"); + Parity=SPACEPARITY; + break; + + case HOST_COM_PARITY_NONE: + sub_note_trace0(HOST_COM_VERBOSE, "Set DISABLE Parity"); + Parity=NOPARITY; + break; + } + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + always_trace1("set PARITY failed - FastCommSetLineControl :%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.Parity = Parity; + break; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::: Setup data bits */ + + case HOST_COM_DATABITS: + sub_note_trace1(HOST_COM_VERBOSE, "Setting data bits %d",arg); + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, &DataBits)) + { + DataBits = (UCHAR)arg; + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + always_trace1("set DATABITS failed - FastCommSetLineControl:%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.DataBits = DataBits; + break; + + /*::::::::::::::::::::::::::::::::::::::: Unrecognised host_com ioctl */ + + default: + always_trace0("Bad host_com_ioctl\n"); + sub_note_trace0(HOST_COM_VERBOSE, "Bad host_com_ioctl"); + break; + } + + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::: Host comms reset ????? */ + +GLOBAL void host_com_reset IFN1(int, adapter) +{ + int controller, line; + half_word IMR_value; + + com_int_data(adapter, &controller, &line); + + always_trace3("com reset Adapter %d, controller %d, line %d\n",adapter,controller,line); + + //Disable interrupts on port being reset + ica_inb((io_addr) (controller ? ICA1_PORT_1 : ICA0_PORT_1), &IMR_value); + IMR_value |= 1 << line; + ica_outb((io_addr) (controller ? ICA1_PORT_1 : ICA0_PORT_1), IMR_value); + + //Enable error displaying + host_com[adapter].DisplayError = TRUE; + host_com[adapter].Suspended = FALSE; + host_com[adapter].Suspending = FALSE; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Autoflush */ + +GLOBAL void host_setup_aflush IFN1(int, state) +{ + UNREFERENCED_FORMAL_PARAMETER(state); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: RX buffer handling routines :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/*:::::::::::::::::::::::::::::::::::::::: Get chars from the serial driver */ + + +DWORD RX GetCharsFromDriver(int adapter) +{ + CURRENT_ADAPTER(); + DWORD bytesread = 0, bytestoread; + OVERLAPPED OV; + DWORD CommError; + DWORD bytes_before_wrap; + DWORD total_bytes_read = 0; + + + OV.hEvent = current->RXEvent; /* Event to signal completion on */ + EnterCriticalSection(¤t->CSEvent); + + bytestoread = BUFFER_SIZE - current->bytes_in_rxbuf; + bytes_before_wrap = BUFFER_SIZE - current->head_inx; + if (bytes_before_wrap < bytestoread){ + OV.Offset = 0; /* reset offset or ReadFile can fail */ + OV.OffsetHigh = 0; + if (!ReadFile(current->handle, ¤t->buffer[current->head_inx], + bytes_before_wrap, &bytesread, &OV)) + { + // we have zero timeout for the read operation + // this pending check may be redundant?????? + if (GetLastError() == ERROR_IO_PENDING) { + GetOverlappedResult(current->handle, &OV, + &bytesread, TRUE); + } + else { + ClearCommError(current->handle, &CommError, NULL); + bytesread = 0; + } + } + + if (bytesread) { + total_bytes_read = bytesread; + current->bytes_in_rxbuf += bytesread; + if (bytesread == bytes_before_wrap) { + current->head_inx = 0; + bytestoread -= bytesread; + } + else { + current->head_inx += bytesread; + bytestoread = 0; + + } + } + else + bytestoread = 0; + } + if (bytestoread){ + OV.Offset = 0; /* reset offset or ReadFile can fail */ + OV.OffsetHigh = 0; + if (!ReadFile(current->handle, ¤t->buffer[current->head_inx], + bytestoread, &bytesread, &OV)) + { + if (GetLastError() == ERROR_IO_PENDING) { + GetOverlappedResult(current->handle, &OV, + &bytesread, TRUE); + } + else { + ClearCommError(current->handle, &CommError, NULL); + bytesread = 0; + } + } + if (bytesread) { + current->bytes_in_rxbuf += bytesread; + current->head_inx += bytesread; + total_bytes_read += bytesread; + } + } + LeaveCriticalSection(¤t->CSEvent); + + return (total_bytes_read); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: RX thread, one per comm port :::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +DWORD PollCommsThread(PVOID pv) +{ + DWORD adapter = (DWORD)pv; + DWORD dwRet = (WORD)-1; + + try { + dwRet = nt_poll_comms(adapter); + } + except(VdmUnhandledExceptionFilter(GetExceptionInformation())) { + ; // we shouldn't arrive here + } + + return dwRet; +} + + + +DWORD CPU nt_poll_comms IFN1(DWORD, adapter) +{ + CURRENT_ADAPTER(); /* Setup ptr to current adapter */ + DWORD EvtMask; /* Comms event mask */ + ULONG SignalledObj = (ULONG) -1; + HANDLE WaitTable[3]; + HANDLE SetCommEvt; /* Handle used by FastSetCommEvent */ + + BOOL CheckDriverForChars = FALSE; /* Check driver for characters */ + RXBUFCHARTYPE CharType; + + /*::::::::::::::::::::::::::::::::: Setup table of event signal objects */ + + WaitTable[0] = current->EvtHandle; + WaitTable[1] = current->RXControlObject; + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Setup comm wait mask */ + + SetCommEvt = CreateEvent(NULL,TRUE,FALSE,NULL); + + FastSetCommMask(current->handle,SetCommEvt,EV_RXCHAR | EV_ERR | EV_MODEM); + + //Initialise FastWaitCommsOrCpuEvent function + FastWaitCommsOrCpuEvent(NULL, NULL, 0, NULL, NULL); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Enter read loop */ + + while(TRUE) + { + /*::::::::::::::::: Wait for communications events then process them */ + + if(SignalledObj != 1) + { + if(!FastWaitCommsOrCpuEvent(current->handle, WaitTable, 0, &EvtMask, + &SignalledObj)) + { + // Error getting comms/CPU thread event ? + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + } + } + + /*::::::::::::::::::::: Is the CPU thread returning control to us ? */ + + if(SignalledObj == 1 || current->TerminateRXThread) + { + // The CPU thread is trying to tell us something. + + /*..................... Is it time to terminate this thread !!! */ + + if(current->TerminateRXThread) + { + FastSetCommMask(current->handle,SetCommEvt,0); + WaitForAllXOFFsToComplete(adapter); // Complete ioctl's + CloseHandle(SetCommEvt); + return(0); // Terminate thread + } + + /* we have 3 reasons why we are here: + (1). the CPU thread has emptied the current rx window + (2). XOFF is in progress + */ + } + + if (SignalledObj == 0 || current->bytes_in_rxwindow == 0) + GetCharsFromDriver(adapter); + /*:::::::::::::::::::::::::::::::: Is there data to pass to the base */ + + if((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY) + { + if (CharType == RXCHAR || CharType == CHARINERROR) { + WaitForAllXOFFsToComplete(adapter); + } + + // slid the window. Note that there may be some character left in + // the window(because of XOFF). It is no harm to slid + // the window. + // + EnterCriticalSection(¤t->CSEvent); + if (current->bytes_in_rxbuf > current->rxwindow_size) + current->bytes_in_rxwindow = current->rxwindow_size; + else + current->bytes_in_rxwindow = current->bytes_in_rxbuf; + LeaveCriticalSection(¤t->CSEvent); + + host_com_lock(adapter); + + if(CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else { + com_recv_char(adapter); + /* + * reset rx flush counter so we won't flush Rx buffer. + * current->RXFlushTrigger may have been RXFLUSHTRIGGER - 1 + * at this moment and when we switch context to main thread + * another timer tick may have come which would trigger + * EmptyRxBuffer and cause unwantted overrun. + */ + current->RXFlushTrigger = RXFLUSHTRIGGER; + current->RX_in_Control = FALSE; + current->SignalRXThread = 0; + } + host_com_unlock(adapter); + + //Wait for CPU thread to return control + if(CharType != MODEMSTATE && CharType != RXERROR) + { + WaitForSingleObject(current->RXControlObject, INFINITE); + } + + SignalledObj = 1; + } + else + SignalledObj = (ULONG) -1; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Wait for XOFF ioctl's to complete ::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + + +void RX WaitForAllXOFFsToComplete(int adapter) +{ + CURRENT_ADAPTER(); + int PendingXOFF; + + if(current->firstStatusBlock == NULL && current->lastStatusBlock == NULL) + return; //list of pending ioctrl's empty + + /*::::::::::::::::::::::: Wait for all pending xoff ioctl's to complete */ + + do + { + PendingXOFF = RemoveCompletedXOFFs(adapter); + + /*................................... Are there any ioctl's pending */ + + if(PendingXOFF) + WaitForSingleObject(current->XOFFEvent,XOFF_TIMEOUT); // wait for ioctl + } + while(PendingXOFF); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Removed completed XOFF ioctl's :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +BOOL RX RemoveCompletedXOFFs(int adapter) +{ + CURRENT_ADAPTER(); + int PendingXOFF; + + /*........................................ Remove completed ioctl's */ + + EnterCriticalSection(¤t->CSEvent); + + PendingXOFF = RemoveCompletedIOCTLs(¤t->firstStatusBlock, + ¤t->lastStatusBlock); + + if(!PendingXOFF) current->XOFFInProgress = FALSE; + + LeaveCriticalSection(¤t->CSEvent); + + return((BOOL) PendingXOFF); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Enter critical section for adapter :::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void RXCPU host_com_lock(int adapter) +{ + CURRENT_ADAPTER(); + if(current->type != ADAPTER_REAL) return; /* Exit, NULL adapter */ + + EnterCriticalSection(¤t->AdapterLock); + current->AdapterLockCnt++; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Leave critical section for adapter :::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void RXCPU host_com_unlock(int adapter) +{ + CURRENT_ADAPTER(); + + if(current->type != ADAPTER_REAL || current->AdapterLockCnt == 0) + return; /* Exit, NULL adapter */ + + current->AdapterLockCnt--; + LeaveCriticalSection(¤t->AdapterLock); + + //Have we been requested to signal the RX thread. After the SetEvent() + //function call the RX thread, which is blocked on the + //current->RXControlObject object, will run. If the SetEvent() function + //is called from within the critical section, then because it is highly + //likely that the RX thread will attempt to perform a host_com_lock(). The + //RX thread will block in the host_com_lock() function until another time + //slice is given to the CPU thread. + + // do not set the event if RX thread already in control + if(current->SignalRXThread && + current->SignalRXThread == GetCurrentThreadId()) + { + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + current->SignalRXThread = (DWORD) 0; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Host coms heart beat ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +//This function is called approximately every 55ms. + +GLOBAL void CPU host_com_heart_beat() +{ + register int adapter; /* Adapter no of adapter being processed */ + register HOST_COM *current; /* Ptr to current adapter being processed */ + DWORD TickCount; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + for(adapter = 0; adapter < (sizeof(host_com)/sizeof(HOST_COM)); adapter++) + { + current = host_com_ptr[adapter]; /* Ptr to current adapter */ + + if(current->type == ADAPTER_NULL) + { + if(current->ReOpenCounter) current->ReOpenCounter--; + } + else if (current->type == ADAPTER_REAL) + { + if(current->no_tx_chars) FlushTXBuffer(adapter,TIMER_TRIGGER); + current->tx_heart_beat_count++; + + if(current->RXFlushTrigger == 0 && !current->CharReadFromUART) + EmptyRXBuffer(adapter); //Empty RX buffer + else + if(current->CharReadFromUART) + { + current->RXFlushTrigger = 0; //Force trigger reset + current->CharReadFromUART = FALSE; + } + + //Update RX flush trigger counter + if(--current->RXFlushTrigger < 0) + current->RXFlushTrigger = RXFLUSHTRIGGER; + /* if auto close is enable, decrement the counter and + * suspend the adapter is time out + */ + + if (current->SuspendTimeoutTicks) { + TickCount = GetTickCount(); + + if (current->TickCount) { + current->SuspendTickCounter -= TickCount - current->TickCount; + } + else { + /* we have not yet initialize the tick count yet, + * presume that it is 55ms + */ + current->SuspendTickCounter -= 55; + } + current->TickCount = TickCount; + + /* time out, suspend the port */ + if (current->SuspendTickCounter <= 27) { + /* make sure host_com_close won't reset the adapter because + * we want to keep the adapter current states + */ + current->Suspending = TRUE; + host_com_close(adapter); + current->Suspended = TRUE; + current->Suspending = FALSE; + } + } + } + } +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Flush TX buffer ::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void CPU FlushTXBuffer(int adapter, FLUSHTYPE FlushReason) +{ + CURRENT_ADAPTER(); + DWORD BytesWritten, error = 0; + + /*................................................. Scale TX threshold */ + + ScaleTXThreshold(current, FlushReason); + + if (current->SyncWrite) { + if (!WriteFile(current->handle, current->TXBuffer, + current->no_tx_chars, &BytesWritten, + ¤t->DWOV[0])) { + error = GetLastError(); + if (error == ERROR_IO_PENDING) { + if (!GetOverlappedResult(current->handle, + ¤t->DWOV[0], + &BytesWritten, + TRUE)) + error = GetLastError(); + else + error = ERROR_SUCCESS; + } + } + if (error != ERROR_SUCCESS) { + ClearCommError(current->handle, &error, NULL); +#ifndef PROD + always_trace2("host_com_write error, adapter %d,%d\n", adapter, error); +#endif + } + tx_shift_register_empty(adapter); + current->no_tx_chars = 0; + return; + } + /*...Clear pending writes on the OV structure that we are about to use*/ + + if(current->DWOV[current->DWOVInx].hEvent) + { + if(GetOverlappedResult(current->handle, + ¤t->DWOV[current->DWOVInx], + &BytesWritten,TRUE)) + { + error = 0; /* Write successful */ + } + else + { + error = GetLastError(); + } + +#ifndef PROD + if(error) + always_trace2("host_com_write error, adapter %d,%d\n",adapter,error); +#endif + + } + else + current->DWOV[current->DWOVInx].hEvent = current->TXEvent[current->DWOVInx]; + + /*..................................................... Write characters */ + + + if(!WriteFile(current->handle, current->TXBuffer, current->no_tx_chars, + &BytesWritten, ¤t->DWOV[current->DWOVInx])) + { + if((error = GetLastError()) == ERROR_IO_PENDING) + error = 0; //ignore IO PENDING + + /* Reset comms port, clear error */ + if(error) + { + ClearCommError(current->handle,&error,NULL); +#ifndef PROD + always_trace2("host_com_write error, adapter %d,%d\n",adapter, + error); +#endif + } + } + + if(++current->DWOVInx == MAX_PENDING_WRITES) current->DWOVInx =0; + current->no_tx_chars = 0; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Scale TX threshold :::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +void ScaleTXThreshold(register HOST_COM *current,FLUSHTYPE FlushReason) +{ + + if(FlushReason != TIMER_TRIGGER) + { + current->tx_timer_flush_count = 0; + current->todate_timer_flush_total = 0; + } + + /*....................................................................*/ + + switch(FlushReason) + { + // Comms heart beat caused flush + + case TIMER_TRIGGER: + //printf("T%d",current->no_tx_chars); + if(++current->tx_timer_flush_count == 3) + { + //printf("X"); + // three consecutive timer trigged flushes, this maybe because + // the TX threshold is to high. If the threshold is to high + // then we are wasting time waiting for the communications + // heart beat to flush the buffer. Reduce TX threshold. + + current->todate_timer_flush_total += current->no_tx_chars; + current->tx_threshold = current->todate_timer_flush_total/3; + + //printf("[%dT]",current->tx_threshold); + + // Reset TXFULL_TRIGGER control variables + current->tx_heart_beat_count = 0; + current->tx_flush_count = 0; + + // Reset TIMER_TRIGGER control variables + current->tx_timer_flush_count = 0; + current->todate_timer_flush_total = 0; + } + else + { + current->todate_timer_flush_total += current->no_tx_chars; + } + + break; + + // TX threshold reached + + case TXFULL_TRIGGER: + + //printf("F"); + //TX scaling trigger triggered ????? + if(current->tx_heart_beat_count <= 3 && + current->tx_flush_count++ == TX_SCALING_TRIGGER) + { + current->tx_threshold = current->tx_threshold*2 > current->max_tx_threshold + ? current->max_tx_threshold + : current->tx_threshold*2; + + //printf("[%dF]",current->tx_threshold); + current->tx_flush_count = 0; + } + else + if(current->tx_heart_beat_count > 3) + { + current->tx_heart_beat_count = 0; + current->tx_flush_count = 0; + } + + break; + + // XOFF triggered or close triggered flush + + case XOFF_TRIGGER: + case CLOSE_TRIGGER: + break; + + } /* End of switch statement */ +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Comms character read hook ::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +//This function is called after a character has been read out of the comms +//adapter (com.c). This function is always called from within an adapter +//critical section, host_com_lock(). + +void CPU host_com_EOI_hook(long adapter) +{ + CURRENT_ADAPTER(); + RXBUFCHARTYPE CharType; + + if (!current->XOFFInProgress && current->bytes_in_rxwindow) + { + while ((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY){ + if (CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else { + com_recv_char((int) adapter); + return; + } + } + } + //Request host_com_unlock() to signal the RX thread. This will + //return responsibility for interrupt generation to the RX thread. + + current->SignalRXThread = GetCurrentThreadId(); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Polling applications LSR hook ::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +// This following function is only called from the comms adapter if data +// available interrupts are disabled and the adapters receive buffer is +// empty. Being called under these circumstances indicates that we +// are dealing with a application that is polling the comms adapter. + +// This function is always called from within an adapter critical section + + +void CPU host_com_poll(int adapter) +{ + CURRENT_ADAPTER(); + RXBUFCHARTYPE CharType; + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + /*::::::::::::::::: Has an XOFF character stop the generation of ints */ + + if(current->XOFFInProgress) + { + // XOFF in process, pass no more characters to the base and return + // control to the RX thread. + + current->SignalRXThread = GetCurrentThreadId(); + return; + } + + // If the RX buffer is empty see if there are any characters hanging + // around in the serial driver + + if(current->bytes_in_rxbuf == 0) GetCharsFromDriver(adapter); + + /*:::::::::::::::::::::: Are there any characters to pass to the base ? */ + + if(current->bytes_in_rxbuf == 0 || + (CharType = GetCharacterTypeInBuffer(current)) == RXBUFEMPTY) + { + current->SignalRXThread = GetCurrentThreadId(); + } + else + { + //Process modem state characters + while(CharType == MODEMSTATE || CharType == RXERROR) + { + if (CharType == MODEMSTATE) + com_modem_change(adapter); + else + com_lsr_change(adapter); + CharType = GetCharacterTypeInBuffer(current); + } + + if(CharType != RXBUFEMPTY) + { + com_recv_char((int)adapter); + } + else + current->SignalRXThread = GetCurrentThreadId(); + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::: Comms adapter data available interrupt hook ::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +// The comms adapter calls this function when the status of the data available +// interrupt has changed. The adapter lock is in affect + +void CPU host_com_da_int_change(int adapter, int data_int_state, int data_state) +{ + CURRENT_ADAPTER(); + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL) + { + // Only attempt to open a null adapter if data available interrupts + // are being enabled + + if(data_int_state == 0 || !host_com_open(adapter)) + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Get the type of character in tail of RX buffer :::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +RXBUFCHARTYPE GetCharacterTypeInBuffer(register HOST_COM *current) +{ + int tail_inx = current->tail_inx; + int bytes_in_buf = current->bytes_in_rxbuf; + RXBUFCHARTYPE rtn; + + //Buffer empty ? + + if(bytes_in_buf == 0) return(RXBUFEMPTY); + + //Escape character at head of buffer + + if(current->buffer[tail_inx] == ESCAPECHAR && bytes_in_buf > 1) + { + BUMP_TAIL_INX(tail_inx,bytes_in_buf); + + switch(current->buffer[tail_inx]) + { + case SERIAL_LSRMST_ESCAPE : + rtn = RXCHAR; + break; + + case SERIAL_LSRMST_LSR_NODATA : + rtn = bytes_in_buf > 1 ? RXERROR : RXBUFEMPTY; + break; + + case SERIAL_LSRMST_LSR_DATA : + rtn = bytes_in_buf > 2 ? CHARINERROR : RXBUFEMPTY; + break; + + case SERIAL_LSRMST_MST : + rtn = bytes_in_buf > 1 ? MODEMSTATE : RXBUFEMPTY; + break; + // receive an invalid escape id + default: + rtn = UNKNOWN; + break; + } + } + else + { + rtn = current->buffer[tail_inx] == ESCAPECHAR ? RXBUFEMPTY : RXCHAR; + } + + return(rtn); +} + + +//::::::::::::::::::::::::::::::::::::Get the next character from the RX buffer. + +void GetCharFromRXBuffer(register HOST_COM *current, RXBUFCHARTYPE type, + UCHAR *data, UCHAR *error) +{ + EnterCriticalSection(¤t->CSEvent); + + switch(type) + { + //................................................. Return modem status + + case MODEMSTATE : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 3; + break; + + //.................................................... Return character + + case RXCHAR : + if(current->buffer[current->tail_inx] == ESCAPECHAR) + { + //Skip ESCAPE character + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow--; + *data = ESCAPECHAR; + } + else + *data = current->buffer[current->tail_inx]; + + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow--; + break; + + //...........................................Return character and error + + case CHARINERROR : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + *error = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 4; + break; + + //................................Return line status error with no data + + case RXERROR : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + // Get linr status error + *error = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 3; + break; + case UNKNOWN: + // The only case we will hit an unknown type is unsupport escape + // id. Dump the escape char, return the byte follows the escape + // characater and post an overrun error + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 2; + *error = 2; + break; + + } + + LeaveCriticalSection(¤t->CSEvent); +} + +//::::::Empty RX buffer, processing characters and changing in the modem status + +void CPU EmptyRXBuffer(int adapter) +{ + RXBUFCHARTYPE CharType; + CURRENT_ADAPTER(); + + if(!current->RX_in_Control && current->SignalRXThread == (DWORD)0) + { + always_trace0("Char not removed from UART, RX buffer flushed\n"); + + host_com_lock(adapter); + + while((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY) + { + if(CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else + com_recv_char(adapter); + } + + host_com_unlock(adapter); + + //Buffer empty return control to the RX thread + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + } +} + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ DEBUG functions + + +#if 0 +void host_com_state(int adapter) +{ + + CURRENT_ADAPTER(); + + printf("Adapter %d\n\n",adapter); + printf("RX in control %s\n", current->RX_in_Control ? "TRUE" : "FALSE"); + printf("XOFFInProgress %s\n", current->XOFFInProgress ? "TRUE" : "FALSE"); + + printf("Head buffer ptr %xh\n",current->head_inx); + printf("Tail buffer ptr %xh\n",current->tail_inx); + printf("Bytes in buffer %d\n",current->bytes_in_rxbuf); + + printf("Bytes in TX buf %d\n",current->no_tx_chars); + printf("TX buf threshold %d\n",current->tx_threshold); + printf("TX threshold max %d\n",current->max_tx_threshold); + printf("TX flush count %d\n",current->tx_flush_count); + printf("TX timer count %d\n",current->tx_heart_beat_count); + + if(current->AdapterLock.DebugInfo) + { + printf("Adapter CS count %d\n",current->AdapterLock.DebugInfo->ContentionCount); + printf("Data CS count %d\n",current->CSEvent.DebugInfo->ContentionCount); + } + + printf("Bytes RX to date %d\n",byte_count); + printf("Last read size %d\n",lastread); + printf("Avg read size %d\n",byte_count && readcount ? byte_count/readcount : 0); + printf("Zero reads %d\n",zeroreads); + + zeroreads = readcount = byte_count=0; + + com_reg_dump(); +} +#endif diff --git a/private/mvdm/softpc.new/host/src/nt_cprgs.c b/private/mvdm/softpc.new/host/src/nt_cprgs.c new file mode 100644 index 000000000..247c546e8 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_cprgs.c @@ -0,0 +1,2351 @@ +/* + SccsID = @(#)sun4_cpuregs.c 1.12 3/27/91 Copyright Insignia Solutions Ltd. +*/ +#include "host_def.h" +#include "insignia.h" +#include "xt.h" +#include CpuH + +#include <stdio.h> + + +/* + * --- SUN_VA CPU Interface Functions --- + * + * There are two sections here. Compile-time define + * the one that is right for you! + * + * CCPU - use the C CPU when HW is not available + * A2CPU - use the assembler CPU when HW is not available + * + */ + + +/* HW and SW HOST_SIMULATE functions. */ +extern void sw_host_simulate (); /* in ccpu.o AND a2cpu.o */ +extern void hw_host_simulate (); /* in hcpu/host/hostsim.c */ + +/* + * The function pointers... + */ +#ifdef CCPU +GLOBAL VOID (*setLDTR_func ) (); +GLOBAL word (*getTR_func ) (); +GLOBAL INT (*getTS_func ) (); +GLOBAL VOID (*setEM_func ) (); +GLOBAL VOID (*setGDTR_limit_func ) (); +GLOBAL VOID (*setIDTR_limit_func ) (); +GLOBAL VOID (*setIOPL_func ) (); +GLOBAL VOID (*setGDTR_base_func ) (); +GLOBAL word (*getLDTR_func ) (); +GLOBAL VOID (*setTR_func ) (); +GLOBAL VOID (*setTS_func ) (); +GLOBAL INT (*getPE_func ) (); +GLOBAL sys_addr (*getGDTR_base_func ) (); +GLOBAL word (*getMSW_reserved_func ) (); +GLOBAL int (*getCPL_func ) (); +GLOBAL INT (*getMP_func ) (); +GLOBAL VOID (*setPE_func ) (); +GLOBAL word (*getGDTR_limit_func ) (); +GLOBAL word (*getIDTR_limit_func ) (); +GLOBAL VOID (*setMSW_reserved_func) (); +GLOBAL VOID (*setMP_func) (); +GLOBAL VOID (*setIDTR_base_func) (); +GLOBAL word (*getNT_func) (); +GLOBAL VOID (*setCPL_func) (); +GLOBAL INT (*getEM_func) (); +GLOBAL VOID (*setNT_func ) (); +GLOBAL sys_addr (*getIDTR_base_func) (); +#endif + +GLOBAL word (*getAX_func) (); +GLOBAL half_word (*getAH_func) (); +GLOBAL half_word (*getAL_func) (); +GLOBAL word (*getBX_func) (); +GLOBAL half_word (*getBH_func) (); +GLOBAL half_word (*getBL_func) (); +GLOBAL word (*getCX_func) (); +GLOBAL half_word (*getCH_func) (); +GLOBAL half_word (*getCL_func) (); +GLOBAL word (*getDX_func) (); +GLOBAL half_word (*getDH_func) (); +GLOBAL half_word (*getDL_func) (); +GLOBAL word (*getSP_func) (); +GLOBAL word (*getBP_func) (); +GLOBAL word (*getSI_func) (); +GLOBAL word (*getDI_func) (); +GLOBAL word (*getIP_func) (); +GLOBAL word (*getCS_func) (); +GLOBAL word (*getDS_func) (); +GLOBAL word (*getES_func) (); +GLOBAL word (*getSS_func) (); +GLOBAL word (*getMSW_func) (); + +#ifdef CCPU +GLOBAL INT (*getDF_func) (); +GLOBAL INT (*getIF_func) (); +GLOBAL INT (*getTF_func) (); +GLOBAL INT (*getPF_func) (); +GLOBAL INT (*getAF_func) (); +GLOBAL INT (*getSF_func) (); +GLOBAL INT (*getZF_func) (); +GLOBAL INT (*getOF_func) (); +GLOBAL INT (*getCF_func) (); +GLOBAL INT (*getIOPL_func ) (); +#endif + +#ifdef A3CPU +GLOBAL word (*getDF_func) (); +GLOBAL word (*getIF_func) (); +GLOBAL word (*getTF_func) (); +GLOBAL word (*getPF_func) (); +GLOBAL word (*getAF_func) (); +GLOBAL word (*getSF_func) (); +GLOBAL word (*getZF_func) (); +GLOBAL word (*getOF_func) (); +GLOBAL word (*getCF_func) (); +GLOBAL word (*getIOPL_func ) (); +#endif + +GLOBAL word (*getSTATUS_func) (); + +GLOBAL double_word (*getOPA_func) (); +GLOBAL double_word (*getOPB_func) (); +GLOBAL double_word (*getOPR_func) (); +GLOBAL sys_addr (*getSSD_func) (); +GLOBAL sys_addr (*getDSD_func) (); + +GLOBAL VOID (*setAX_func) (); +GLOBAL VOID (*setAH_func) (); +GLOBAL VOID (*setAL_func) (); +GLOBAL VOID (*setBX_func) (); +GLOBAL VOID (*setBH_func) (); +GLOBAL VOID (*setBL_func) (); +GLOBAL VOID (*setCX_func) (); +GLOBAL VOID (*setCH_func) (); +GLOBAL VOID (*setCL_func) (); +GLOBAL VOID (*setDX_func) (); +GLOBAL VOID (*setDH_func) (); +GLOBAL VOID (*setDL_func) (); +GLOBAL VOID (*setSP_func) (); +GLOBAL VOID (*setBP_func) (); +GLOBAL VOID (*setSI_func) (); +GLOBAL VOID (*setDI_func) (); +GLOBAL VOID (*setIP_func) (); +GLOBAL INT (*setCS_func) (); +GLOBAL INT (*setDS_func) (); +GLOBAL INT (*setES_func) (); +GLOBAL INT (*setSS_func) (); +GLOBAL VOID (*setMSW_func) (); +GLOBAL VOID (*setDF_func) (); +GLOBAL VOID (*setIF_func) (); +GLOBAL VOID (*setTF_func) (); +GLOBAL VOID (*setPF_func) (); +GLOBAL VOID (*setAF_func) (); +GLOBAL VOID (*setSF_func) (); +GLOBAL VOID (*setZF_func) (); +GLOBAL VOID (*setOF_func) (); +GLOBAL VOID (*setCF_func) (); + +GLOBAL VOID (*setOPLEN_func) (); +GLOBAL VOID (*setOPA_func) (); +GLOBAL VOID (*setOPB_func) (); +GLOBAL VOID (*setOPR_func) (); + +GLOBAL VOID (*host_simulate_func) (); + +#ifdef CPU_30_STYLE + +#ifdef CCPU + +GLOBAL VOID load_sw_cpu_access_functions() +{ + IMPORT VOID c_cpu_simulate(); + + fprintf (stderr,"[load_sw_cpu_access_functions] init READ/WRITE functions.\n"); + + /* READ functions */ + getAX_func = c_getAX; + getAH_func = c_getAH; + getAL_func = c_getAL; + getBX_func = c_getBX; + getBH_func = c_getBH; + getBL_func = c_getBL; + getCX_func = c_getCX; + getCH_func = c_getCH; + getCL_func = c_getCL; + getDX_func = c_getDX; + getDH_func = c_getDH; + getDL_func = c_getDL; + getSP_func = c_getSP; + getBP_func = c_getBP; + getSI_func = c_getSI; + getDI_func = c_getDI; + getIP_func = c_getIP; + getCS_func = c_getCS; + getDS_func = c_getDS; + getES_func = c_getES; + getSS_func = c_getSS; + getMSW_func = c_getMSW; + getDF_func = c_getDF; + getIF_func = c_getIF; + getTF_func = c_getTF; + getPF_func = c_getPF; + getAF_func = c_getAF; + getSF_func = c_getSF; + getZF_func = c_getZF; + getOF_func = c_getOF; + getCF_func = c_getCF; + + + /* WRITE functions */ + setAX_func = c_setAX; + setAH_func = c_setAH; + setAL_func = c_setAL; + setBX_func = c_setBX; + setBH_func = c_setBH; + setBL_func = c_setBL; + setCX_func = c_setCX; + setCH_func = c_setCH; + setCL_func = c_setCL; + setDX_func = c_setDX; + setDH_func = c_setDH; + setDL_func = c_setDL; + setSP_func = c_setSP; + setBP_func = c_setBP; + setSI_func = c_setSI; + setDI_func = c_setDI; + setIP_func = c_setIP; + setDF_func = c_setDF; + setIF_func = c_setIF; + setTF_func = c_setTF; + setPF_func = c_setPF; + setAF_func = c_setAF; + setSF_func = c_setSF; + setZF_func = c_setZF; + setOF_func = c_setOF; + setCF_func = c_setCF; + setSS_func = c_setSS; + setDS_func = c_setDS; + setES_func = c_setES; + setCS_func = c_setCS; + + /* SW HOST_SIMULATE function */ + host_simulate_func = c_cpu_simulate; +} +#endif /* CCPU */ + + +/* Temporary 3.0 stubs... */ +#ifdef A3CPU + +LOCAL double_word a3_na_gOPA() +{ + printf ("%s:%d - getOPA() not supported.\n", __FILE__, __LINE__); + return 0; +} +LOCAL double_word a3_na_gOPB() +{ + printf ("%s:%d - getOPB() not supported.\n", __FILE__, __LINE__); + return 0; +} +LOCAL double_word a3_na_gOPR () +{ + printf ("%s:%d - getOPR() not supported.\n", __FILE__, __LINE__); + return 0; +} +LOCAL sys_addr a3_na_gSSD() +{ + printf ("%s:%d - getSSD() not supported.\n", __FILE__, __LINE__); + return 0; +} +LOCAL sys_addr a3_na_gDSD() +{ + printf ("%s:%d - getDSD() not supported.\n", __FILE__, __LINE__); + return 0; +} +LOCAL VOID a3_na_sOPLEN() +{ + printf ("%s:%d - setOPLEN() not supported.\n", __FILE__, __LINE__); +} +LOCAL VOID a3_na_sOPA() +{ + printf ("%s:%d - setOPA() not supported.\n", __FILE__, __LINE__); +} +LOCAL VOID a3_na_sOPB() +{ + printf ("%s:%d - setOPB() not supported.\n", __FILE__, __LINE__); +} +LOCAL VOID a3_na_sOPR() +{ + printf ("%s:%d - setOPR() not supported.\n", __FILE__, __LINE__); +} +LOCAL VOID a3_na_sMSW() +{ + printf ("%s:%d - setMSW() not supported.\n", __FILE__, __LINE__); +} + +GLOBAL VOID load_sw_cpu_access_functions () +{ + IMPORT VOID _asm_simulate(); + + fprintf (stderr,"[load_sw_cpu_access_functions] init READ/WRITE functions.\n"); + + /* READ functions */ + getAX_func = a3_getAX; + getAH_func = a3_getAH; + getAL_func = a3_getAL; + getBX_func = a3_getBX; + getBH_func = a3_getBH; + getBL_func = a3_getBL; + getCX_func = a3_getCX; + getCH_func = a3_getCH; + getCL_func = a3_getCL; + getDX_func = a3_getDX; + getDH_func = a3_getDH; + getDL_func = a3_getDL; + getSP_func = a3_getSP; + getBP_func = a3_getBP; + getSI_func = a3_getSI; + getDI_func = a3_getDI; + getIP_func = a3_getIP; + getOPA_func = a3_na_gOPA; + getOPB_func = a3_na_gOPB; + getOPR_func = a3_na_gOPR; + getSSD_func = a3_na_gSSD; + getDSD_func = a3_na_gDSD; + getCS_func = a3_getCS; + getDS_func = a3_getDS; + getES_func = a3_getES; + getSS_func = a3_getSS; + getMSW_func = a3_getMSW; + getDF_func = a3_getDF; + getIF_func = a3_getIF; + getTF_func = a3_getTF; + getPF_func = a3_getPF; + getAF_func = a3_getAF; + getSF_func = a3_getSF; + getZF_func = a3_getZF; + getOF_func = a3_getOF; + getCF_func = a3_getCF; + + + /* WRITE functions */ + setAX_func = a3_setAX; + setAH_func = a3_setAH; + setAL_func = a3_setAL; + setBX_func = a3_setBX; + setBH_func = a3_setBH; + setBL_func = a3_setBL; + setCX_func = a3_setCX; + setCH_func = a3_setCH; + setCL_func = a3_setCL; + setDX_func = a3_setDX; + setDH_func = a3_setDH; + setDL_func = a3_setDL; + setSP_func = a3_setSP; + setBP_func = a3_setBP; + setSI_func = a3_setSI; + setDI_func = a3_setDI; + setIP_func = a3_setIP; + setMSW_func = a3_na_sMSW; + setDF_func = a3_setDF; + setIF_func = a3_setIF; + setTF_func = a3_setTF; + setPF_func = a3_setPF; + setAF_func = a3_setAF; + setSF_func = a3_setSF; + setZF_func = a3_setZF; + setOF_func = a3_setOF; + setCF_func = a3_setCF; + setOPLEN_func = a3_na_sOPLEN; + setOPA_func = a3_na_sOPA; + setOPB_func = a3_na_sOPB; + setOPR_func = a3_na_sOPR; + setSS_func = a3_setSS; + setDS_func = a3_setDS; + setES_func = a3_setES; + setCS_func = a3_setCS; + + /* SW HOST_SIMULATE function */ + host_simulate_func = _asm_simulate; +} +#endif /* A3CPU */ + +#else /* CPU_30_STYLE */ + + +#ifdef CCPU +/* + * ---------------------------------------- + * ---- SUN_VA Soft CCPU Interface ---- + * ---------------------------------------- + */ + +extern reg A; +extern reg B; +extern reg C; +extern reg D; +extern reg SP; +extern reg BP; +extern reg SI; +extern reg DI; +extern reg CS; +extern reg DS; +extern reg SS; +extern reg ES; +extern reg IP; + +extern word m_s_w; + +extern void ext_load_CS(); +extern void ext_load_DS(); +extern void ext_load_ES(); +extern void ext_load_SS(); + + +word soft_ccpu_getAX () +{ + return (A.X); +} + +half_word soft_ccpu_getAH () +{ + return (A.byte.high); +} + +half_word soft_ccpu_getAL () +{ + return (A.byte.low); +} + +word soft_ccpu_getBX () +{ + return (B.X); +} + +half_word soft_ccpu_getBH () +{ + return (B.byte.high); +} + +half_word soft_ccpu_getBL () +{ + return (B.byte.low); +} + +word soft_ccpu_getCX () +{ + return (C.X); +} + +half_word soft_ccpu_getCH () +{ + return (C.byte.high); +} + +half_word soft_ccpu_getCL () +{ + return (C.byte.low); +} + +word soft_ccpu_getDX () +{ + return (D.X); +} + +half_word soft_ccpu_getDH () +{ + return (D.byte.high); +} + +half_word soft_ccpu_getDL () +{ + return (D.byte.low); +} + +word soft_ccpu_getSP () +{ + return (SP.X); +} + +word soft_ccpu_getBP () +{ + return (BP.X); +} + +word soft_ccpu_getSI () +{ + return (SI.X); +} + +word soft_ccpu_getDI () +{ + return (DI.X); +} + +word soft_ccpu_getIP () +{ + return (IP.X); +} + +word soft_ccpu_getCS () +{ + return (CS.X); +} + +word soft_ccpu_getDS () +{ + return (DS.X); +} + +word soft_ccpu_getES () +{ + return (ES.X); +} + +word soft_ccpu_getSS () +{ + return (SS.X); +} + +word soft_ccpu_getMSW () +{ + return ((m_s_w)); +} + +word soft_ccpu_getDF () +{ + return (STATUS_DF); +} + +word soft_ccpu_getIF () +{ + return (STATUS_IF); +} + +word soft_ccpu_getTF () +{ + return (STATUS_TF); +} + +word soft_ccpu_getPF () +{ + return (STATUS_PF); +} + +word soft_ccpu_getAF () +{ + return (STATUS_AF); +} + +word soft_ccpu_getSF () +{ + return (STATUS_SF); +} + +word soft_ccpu_getZF () +{ + return (STATUS_ZF); +} + +word soft_ccpu_getOF () +{ + return (STATUS_OF); +} + +word soft_ccpu_getCF () +{ + return (STATUS_CF); +} + +word soft_ccpu_getSTATUS () +{ + return (getCF() | + getOF() << 11 | + getZF() << 6 | + getSF() << 7 | + getAF() << 4 | + getPF() << 2 | + getTF() << 8 | + getIF() << 9 | + getDF() << 10 | + getIOPL() << 12 | + getNT() << 14); +} + +int soft_ccpu_getCPL () +{ + return (CPL); +} + +sys_addr soft_ccpu_getGDTR_base () +{ + return (GDTR_base); +} + +sys_addr soft_ccpu_getIDTR_base () +{ + return (IDTR_base); +} + +word soft_ccpu_getGDTR_limit () +{ + return (GDTR_limit); +} + +word soft_ccpu_getIDTR_limit () +{ + return (IDTR_limit); +} + +word soft_ccpu_getLDTR () +{ + return (LDTR.X); +} + +word soft_ccpu_getTR () +{ + return (TR.X); +} + +word soft_ccpu_getMSW_reserved () +{ + return (MSW.reserved); +} + +word soft_ccpu_getTS () +{ + return (MSW.TS); +} + +word soft_ccpu_getEM () +{ + return (MSW.EM); +} + +word soft_ccpu_getMP () +{ + return (MSW.MP); +} + +word soft_ccpu_getPE () +{ + return (MSW.PE); +} + +word soft_ccpu_getNT () +{ + return (STATUS_NT); +} + +word soft_ccpu_getIOPL () +{ + return (STATUS_IOPL); +} + +void soft_ccpu_setAX (val) +unsigned int val; +{ + A.X = val; +} + +void soft_ccpu_setAH (val) +unsigned int val; +{ + A.byte.high = val; +} + +void soft_ccpu_setAL (val) +unsigned int val; +{ + A.byte.low = val; +} + +void soft_ccpu_setBX (val) +unsigned int val; +{ + B.X = val; +} + +void soft_ccpu_setBH (val) +unsigned int val; +{ + B.byte.high = val; +} + +void soft_ccpu_setBL (val) +unsigned int val; +{ + B.byte.low = val; +} + +void soft_ccpu_setCX (val) +unsigned int val; +{ + C.X = val; +} + +void soft_ccpu_setCH (val) +unsigned int val; +{ + C.byte.high = val; +} + +void soft_ccpu_setCL (val) +unsigned int val; +{ + C.byte.low = val; +} + +void soft_ccpu_setDX (val) +unsigned int val; +{ + D.X = val; +} + +void soft_ccpu_setDH (val) +unsigned int val; +{ + D.byte.high = val; +} + +void soft_ccpu_setDL (val) +unsigned int val; +{ + D.byte.low = val; +} + +void soft_ccpu_setSP (val) +unsigned int val; +{ + SP.X = val; +} + +void soft_ccpu_setBP (val) +unsigned int val; +{ + BP.X = val; +} + +void soft_ccpu_setSI (val) +unsigned int val; +{ + SI.X = val; +} + +void soft_ccpu_setDI (val) +unsigned int val; +{ + DI.X = val; +} + +void soft_ccpu_setIP (val) +unsigned int val; +{ + IP.X = val; +} + +void soft_ccpu_setMSW (val) +unsigned int val; +{ + m_s_w = val; +} + +void soft_ccpu_setDF (val) +unsigned int val; +{ + STATUS_DF = val; +} + +void soft_ccpu_setIF (val) +unsigned int val; +{ + STATUS_IF = val; +} + +void soft_ccpu_setTF (val) +unsigned int val; +{ + STATUS_TF = val; +} + +void soft_ccpu_setPF (val) +unsigned int val; +{ + STATUS_PF = val; +} + +void soft_ccpu_setAF (val) +unsigned int val; +{ + STATUS_AF = val; +} + +void soft_ccpu_setSF (val) +unsigned int val; +{ + STATUS_SF = val; +} + +void soft_ccpu_setZF (val) +unsigned int val; +{ + STATUS_ZF = val; +} + +void soft_ccpu_setOF (val) +unsigned int val; +{ + STATUS_OF = val; +} + +void soft_ccpu_setCF (val) +unsigned int val; +{ + STATUS_CF = val; +} + +void soft_ccpu_setCPL ( val ) +int val; +{ + CPL = val; +} + +void soft_ccpu_setGDTR_base ( val ) +sys_addr val; +{ + GDTR_base = val; +} + +void soft_ccpu_setIDTR_base ( val ) +sys_addr val; +{ + IDTR_base = val; +} + +void soft_ccpu_setGDTR_limit ( val ) +word val; +{ + GDTR_limit = val; +} + +void soft_ccpu_setIDTR_limit ( val ) +word val; +{ + IDTR_limit = val; +} + +void soft_ccpu_setLDTR ( val ) +word val; +{ + LDTR.X = val; +} + +void soft_ccpu_setTR ( val ) +word val; +{ + TR.X = val; +} + +void soft_ccpu_setMSW_reserved ( val ) +word val; +{ + MSW.reserved = val; +} + +void soft_ccpu_setTS ( val ) +word val; +{ + MSW.TS = val; +} + +void soft_ccpu_setEM ( val ) +word val; +{ + MSW.EM = val; +} + +void soft_ccpu_setMP ( val ) +word val; +{ + MSW.MP = val; +} + +void soft_ccpu_setPE ( val ) +word val; +{ + MSW.PE = val; +} + +void soft_ccpu_setNT ( val ) +word val; +{ + STATUS_NT = val; +} + +void soft_ccpu_setIOPL ( val ) +word val; +{ + STATUS_IOPL = val; +} + + + + + +void +load_sw_cpu_access_functions () +{ + /* READ functions */ + getAX_func = soft_ccpu_getAX; + getAH_func = soft_ccpu_getAH; + getAL_func = soft_ccpu_getAL; + getBX_func = soft_ccpu_getBX; + getBH_func = soft_ccpu_getBH; + getBL_func = soft_ccpu_getBL; + getCX_func = soft_ccpu_getCX; + getCH_func = soft_ccpu_getCH; + getCL_func = soft_ccpu_getCL; + getDX_func = soft_ccpu_getDX; + getDH_func = soft_ccpu_getDH; + getDL_func = soft_ccpu_getDL; + getSP_func = soft_ccpu_getSP; + getBP_func = soft_ccpu_getBP; + getSI_func = soft_ccpu_getSI; + getDI_func = soft_ccpu_getDI; + getIP_func = soft_ccpu_getIP; + getCS_func = soft_ccpu_getCS; + getDS_func = soft_ccpu_getDS; + getES_func = soft_ccpu_getES; + getSS_func = soft_ccpu_getSS; + getMSW_func = soft_ccpu_getMSW; + getDF_func = soft_ccpu_getDF; + getIF_func = soft_ccpu_getIF; + getTF_func = soft_ccpu_getTF; + getPF_func = soft_ccpu_getPF; + getAF_func = soft_ccpu_getAF; + getSF_func = soft_ccpu_getSF; + getZF_func = soft_ccpu_getZF; + getOF_func = soft_ccpu_getOF; + getCF_func = soft_ccpu_getCF; + getSTATUS_func = soft_ccpu_getSTATUS; /* not used in a2CPU */ + getCPL_func = soft_ccpu_getCPL; /* not used in a2CPU */ + getGDTR_base_func = soft_ccpu_getGDTR_base; /* not used in a2CPU */ + getGDTR_limit_func = soft_ccpu_getGDTR_limit; /* not used in a2CPU */ + getIDTR_base_func = soft_ccpu_getIDTR_base; /* not used in a2CPU */ + getIDTR_limit_func = soft_ccpu_getIDTR_limit; /* not used in a2CPU */ + getLDTR_func = soft_ccpu_getLDTR; /* not used in a2CPU */ + getTR_func = soft_ccpu_getTR; /* not used in a2CPU */ + getMSW_reserved_func = soft_ccpu_getMSW_reserved; /* not used in a2CPU */ + getTS_func = soft_ccpu_getTS; /* not used in a2CPU */ + getEM_func = soft_ccpu_getEM; /* not used in a2CPU */ + getMP_func = soft_ccpu_getMP; /* not used in a2CPU */ + getPE_func = soft_ccpu_getPE; /* not used in a2CPU */ + getNT_func = soft_ccpu_getNT; /* not used in a2CPU */ + getIOPL_func = soft_ccpu_getIOPL; /* not used in a2CPU */ + + + /* WRITE functions */ + setAX_func = soft_ccpu_setAX; + setAH_func = soft_ccpu_setAH; + setAL_func = soft_ccpu_setAL; + setBX_func = soft_ccpu_setBX; + setBH_func = soft_ccpu_setBH; + setBL_func = soft_ccpu_setBL; + setCX_func = soft_ccpu_setCX; + setCH_func = soft_ccpu_setCH; + setCL_func = soft_ccpu_setCL; + setDX_func = soft_ccpu_setDX; + setDH_func = soft_ccpu_setDH; + setDL_func = soft_ccpu_setDL; + setSP_func = soft_ccpu_setSP; + setBP_func = soft_ccpu_setBP; + setSI_func = soft_ccpu_setSI; + setDI_func = soft_ccpu_setDI; + setIP_func = soft_ccpu_setIP; + setCS_func = ext_load_CS; + setDS_func = ext_load_DS; + setES_func = ext_load_ES; + setSS_func = ext_load_SS; + setMSW_func = soft_ccpu_setMSW; + setDF_func = soft_ccpu_setDF; + setIF_func = soft_ccpu_setIF; + setTF_func = soft_ccpu_setTF; + setPF_func = soft_ccpu_setPF; + setAF_func = soft_ccpu_setAF; + setSF_func = soft_ccpu_setSF; + setZF_func = soft_ccpu_setZF; + setOF_func = soft_ccpu_setOF; + setCF_func = soft_ccpu_setCF; + setCPL_func = soft_ccpu_setCPL; /* not used in a2CPU */ + setGDTR_base_func = soft_ccpu_setGDTR_base; /* not used in a2CPU */ + setGDTR_limit_func = soft_ccpu_setGDTR_limit; /* not used in a2CPU */ + setIDTR_base_func = soft_ccpu_setIDTR_base; /* not used in a2CPU */ + setIDTR_limit_func = soft_ccpu_setIDTR_limit; /* not used in a2CPU */ + setLDTR_func = soft_ccpu_setLDTR; /* not used in a2CPU */ + setTR_func = soft_ccpu_setTR; /* not used in a2CPU */ + setMSW_reserved_func = soft_ccpu_setMSW_reserved; /* not used in a2CPU */ + setTS_func = soft_ccpu_setTS; /* not used in a2CPU */ + setEM_func = soft_ccpu_setEM; /* not used in a2CPU */ + setMP_func = soft_ccpu_setMP; /* not used in a2CPU */ + setPE_func = soft_ccpu_setPE; /* not used in a2CPU */ + setNT_func = soft_ccpu_setNT; /* not used in a2CPU */ + setIOPL_func = soft_ccpu_setIOPL; /* not used in a2CPU */ + + /* SW HOST_SIMULATE function */ + host_simulate_func = sw_host_simulate; +} +#endif CCPU + + + + + + + + + + + + + + + +#ifdef A2CPU +/* + * -------------------------------------------- + * ---- SUN_VA Assember CCPU Interface ---- + * -------------------------------------------- + */ + +/* need extern definition for M[] */ +#include "sas.h" + +extern sreg INTEL_STATUS; +extern void (*R_ROUTE)(); +extern int R_INTR; +extern reg R_AX; /* Accumulator */ +extern reg R_BX; /* Base */ +extern reg R_CX; /* Count */ +extern reg R_DX; /* Data */ +extern reg R_SP; /* Stack Pointer */ +extern reg R_BP; /* Base pointer */ +extern reg R_SI; /* Source Index */ +extern reg R_DI; /* Destination Index */ + +extern double_word R_OPA; +extern double_word R_OPB; +extern double_word R_OPR; +extern int R_MISC_FLAGS; + +extern sys_addr R_IP; /* Instruction Pointer */ + +extern sys_addr R_ACT_CS; /* Code Segment */ +extern sys_addr R_ACT_DS; /* Data Segment */ +extern sys_addr R_ACT_SS; /* Stack Segment */ +extern sys_addr R_ACT_ES; /* Extra Segment */ + +extern sys_addr R_DEF_SS; /* Default SS register */ +extern sys_addr R_DEF_DS; /* Default DS register */ + +extern void do_setSF(); +extern void do_setOF(); +extern void do_setPF(); +extern void do_setZF(); +extern void do_setCF(); + + +word soft_a2cpu_getAX () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getAX\n"); +#endif MIKE_DEBUG + return (R_AX.X); +} + +half_word soft_a2cpu_getAH () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getAH\n"); +#endif MIKE_DEBUG + return (R_AX.byte.high); +} + +half_word soft_a2cpu_getAL () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getAL\n"); +#endif MIKE_DEBUG + return (R_AX.byte.low); +} + +word soft_a2cpu_getBX () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getBX\n"); +#endif MIKE_DEBUG + return (R_BX.X); +} + +half_word soft_a2cpu_getBH () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getBH\n"); +#endif MIKE_DEBUG + return (R_BX.byte.high); +} + +half_word soft_a2cpu_getBL () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getBL\n"); +#endif MIKE_DEBUG + return (R_BX.byte.low); +} + +word soft_a2cpu_getCX () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getCX\n"); +#endif MIKE_DEBUG + return (R_CX.X); +} + +half_word soft_a2cpu_getCH () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getCH\n"); +#endif MIKE_DEBUG + return (R_CX.byte.high); +} + +half_word soft_a2cpu_getCL () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getCL\n"); +#endif MIKE_DEBUG + return (R_CX.byte.low); +} + +word soft_a2cpu_getDX () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDX\n"); +#endif MIKE_DEBUG + return (R_DX.X); +} + +half_word soft_a2cpu_getDH () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDH\n"); +#endif MIKE_DEBUG + return (R_DX.byte.high); +} + +half_word soft_a2cpu_getDL () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDL\n"); +#endif MIKE_DEBUG + return (R_DX.byte.low); +} + +word soft_a2cpu_getSP () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getSP\n"); +#endif MIKE_DEBUG + return (R_SP.X); +} + +word soft_a2cpu_getBP () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getBP\n"); +#endif MIKE_DEBUG + return (R_BP.X); +} + +word soft_a2cpu_getSI () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getSI\n"); +#endif MIKE_DEBUG + return (R_SI.X); +} + +word soft_a2cpu_getDI () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDI\n"); +#endif MIKE_DEBUG + return (R_DI.X); +} + +word soft_a2cpu_getIP () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getIP\n"); +#endif MIKE_DEBUG + return (R_IP - (sys_addr)M - (sys_addr)(getCS() << 4) ); +} + + +double_word soft_a2cpu_getOPA () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getOPA\n"); +#endif MIKE_DEBUG + return (R_OPA); +} + +double_word soft_a2cpu_getOPB () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getOPB\n"); +#endif MIKE_DEBUG + return (R_OPB); +} + +double_word soft_a2cpu_getOPR () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getOPR=0x%x\n",R_OPR); +#endif MIKE_DEBUG + return (R_OPR); +} + +sys_addr soft_a2cpu_getSSD () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getSSD\n"); +#endif MIKE_DEBUG + return ((R_ACT_SS - (sys_addr)M) >> 4); +} + +sys_addr soft_a2cpu_getDSD () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDSD\n"); +#endif MIKE_DEBUG + return ((R_ACT_DS - (sys_addr)M) >> 4); +} + +word soft_a2cpu_getCS () +{ +#ifdef MIKE_DEBUG +unsigned int tmp; + + tmp = ((R_ACT_CS - (sys_addr)M) >> 4); + fprintf (stderr,"getCS, return=0x%x [M=0x%x R_ACT_CS=0x%x]\n",tmp,M,R_ACT_CS); +#endif MIKE_DEBUG + return ((R_ACT_CS - (sys_addr)M) >> 4); +} + +word soft_a2cpu_getDS () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDS\n"); +#endif MIKE_DEBUG + return (getDSD()); +} + +word soft_a2cpu_getES () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getES\n"); +#endif MIKE_DEBUG + return ((R_ACT_ES - (sys_addr)M) >> 4); +} + +word soft_a2cpu_getSS () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getSS\n"); +#endif MIKE_DEBUG + return (getSSD()); +} + +word soft_a2cpu_getMSW () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getMSW\n"); +#endif MIKE_DEBUG + return ((m_s_w)); +} + +word soft_a2cpu_getDF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getDF\n"); +#endif MIKE_DEBUG + return (INTEL_STATUS.DF); +} + +word soft_a2cpu_getIF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getIF\n"); +#endif MIKE_DEBUG + return (INTEL_STATUS.IF); +} + +word soft_a2cpu_getTF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getTF\n"); +#endif MIKE_DEBUG + return (INTEL_STATUS.TF); +} + +word soft_a2cpu_getPF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getPF=0x%x\n",pf_table[getOPR() & 0xff]); +#endif MIKE_DEBUG + return (pf_table[getOPR() & 0xff]); +} + +word soft_a2cpu_getAF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getAF\n"); +#endif MIKE_DEBUG + return (((((getOPA()) ^ (getOPB())) ^ (getOPR())) >> 4) & 1); +} + +word soft_a2cpu_getSF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getSF\n"); +#endif MIKE_DEBUG + return ((IS_BYTE_OP ? getOPR() >> 7 : getOPR() >> 15 ) & 1); +} + +word soft_a2cpu_getZF () +{ +#ifdef MIKE_DEBUG +word tmp; + + tmp = (REALLY_ZERO ? 1 : (IS_BYTE_OP ? ((getOPR() & 0xff) ? 0 : 1) : ((getOPR() & 0xffff) ? 0 : 1))); + fprintf (stderr,"getZF=0x%x\n",tmp); +#endif MIKE_DEBUG + return (REALLY_ZERO ? 1 : (IS_BYTE_OP ? ((getOPR() & 0xff) ? 0 : 1) : ((getOPR() & 0xffff) ? 0 : 1))); +} + +word soft_a2cpu_getOF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getOF\n"); +#endif MIKE_DEBUG + return ((IS_BYTE_OP ? (((getOPR() ^ getOPA() ^ getOPB()) ^ (getOPR() >> 1)) >> 7) & 1 : ((getOPR() ^ getOPA() ^ getOPB()) ^ (getOPR() >> 1)) >> 15 ) & 1 ); +} + +word soft_a2cpu_getCF () +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"getCF\n"); +#endif MIKE_DEBUG + return ((IS_BYTE_OP ? getOPR() >> 8 : getOPR() >> 16) & 1); +} + + +#define getRET() +#define setRET(x) + + +void soft_a2cpu_setAX (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setAX\n"); +#endif MIKE_DEBUG + R_AX.X = val; +} + +void soft_a2cpu_setAH (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setAH\n"); +#endif MIKE_DEBUG + R_AX.byte.high = val; +} + +void soft_a2cpu_setAL (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setAL\n"); +#endif MIKE_DEBUG + R_AX.byte.low = val; +} + +void soft_a2cpu_setBX (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setBX\n"); +#endif MIKE_DEBUG + R_BX.X = val; +} + +void soft_a2cpu_setBH (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setBH\n"); +#endif MIKE_DEBUG + R_BX.byte.high = val; +} + +void soft_a2cpu_setBL (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setBL\n"); +#endif MIKE_DEBUG + R_BX.byte.low = val; +} + +void soft_a2cpu_setCX (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setCX\n"); +#endif MIKE_DEBUG + R_CX.X = val; +} + +void soft_a2cpu_setCH (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setCH\n"); +#endif MIKE_DEBUG + R_CX.byte.high = val; +} + +void soft_a2cpu_setCL (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setCL\n"); +#endif MIKE_DEBUG + R_CX.byte.low = val; +} + +void soft_a2cpu_setDX (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setDX\n"); +#endif MIKE_DEBUG + R_DX.X = val; +} + +void soft_a2cpu_setDH (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setDH\n"); +#endif MIKE_DEBUG + R_DX.byte.high = val; +} + +void soft_a2cpu_setDL (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setDL\n"); +#endif MIKE_DEBUG + R_DX.byte.low = val; +} + +void soft_a2cpu_setSP (val) +unsigned int val; +{ + R_SP.X = val; +#ifdef MIKE_DEBUG + fprintf (stderr,"setSP to 0x%x [val=0x%x]\n",R_SP.X,val); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setBP (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setBP\n"); +#endif MIKE_DEBUG + R_BP.X = val; +} + +void soft_a2cpu_setSI (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setSI\n"); +#endif MIKE_DEBUG + R_SI.X = val; +} + +void soft_a2cpu_setDI (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setDI\n"); +#endif MIKE_DEBUG + R_DI.X = val; +} + +void soft_a2cpu_setIP (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG +unsigned int tmp; +#endif MIKE_DEBUG + + R_IP = val + (sys_addr)M +(sys_addr) (getCS() << 4); +#ifdef MIKE_DEBUG + tmp = getCS (); + fprintf (stderr,"setIP to 0x%x [M=0x%x getCS()=0x%x]\n",R_IP,M,tmp); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setMSW (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setMSW\n"); +#endif MIKE_DEBUG + m_s_w = val; +} + +void soft_a2cpu_setDF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setDF\n"); +#endif MIKE_DEBUG + INTEL_STATUS.DF = val; +} + +void soft_a2cpu_setIF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setIF\n"); +#endif MIKE_DEBUG + INTEL_STATUS.IF = val; +} + +void soft_a2cpu_setTF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setTF\n"); +#endif MIKE_DEBUG + INTEL_STATUS.TF = val; +} + +void soft_a2cpu_setPF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG +word tmp; +#endif MIKE_DEBUG + + do_setPF (val); +#ifdef MIKE_DEBUG + tmp = soft_a2cpu_getPF(); + fprintf (stderr,"setPF to 0x%x. Read back as 0x%x\n",val,tmp); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setAF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setAF\n"); +#endif MIKE_DEBUG + setOPA (val << 4); + setOPB (getOPR() & 0x7f); +} + +void soft_a2cpu_setSF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setSF\n"); +#endif MIKE_DEBUG + do_setSF (val); +} + +void soft_a2cpu_setZF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setZF\n"); +#endif MIKE_DEBUG + do_setZF (val); +} + +void soft_a2cpu_setOF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setOF\n"); +#endif MIKE_DEBUG + do_setOF (val); +} + +void soft_a2cpu_setCF (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setCF\n"); +#endif MIKE_DEBUG + do_setCF (val); +} + +void soft_a2cpu_setOPLEN (val) +unsigned int val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setOPLEN\n"); +#endif MIKE_DEBUG + R_MISC_FLAGS &= 0x7fffffff; + R_MISC_FLAGS |= val; +} + +void soft_a2cpu_setOPA (val) +double_word val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setOPA\n"); +#endif MIKE_DEBUG + R_OPA = val; +} + +void soft_a2cpu_setOPB (val) +double_word val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setOPB\n"); +#endif MIKE_DEBUG + R_OPB = val; +} + +void soft_a2cpu_setOPR (val) +double_word val; +{ +#ifdef MIKE_DEBUG + fprintf (stderr,"setOPR\n"); +#endif MIKE_DEBUG + R_OPR = val; +} + +void soft_a2cpu_setSS (val) +sys_addr val; +{ + R_ACT_SS = (sys_addr)M + (val << 4); +#ifdef MIKE_DEBUG + fprintf (stderr,"setSS to 0x%x [M=0x%x,val=0x%x]\n",R_ACT_SS,M,val); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setDS (val) +sys_addr val; +{ + R_ACT_DS = (sys_addr)M + (val << 4); +#ifdef MIKE_DEBUG + fprintf (stderr,"setDS to 0x%x [M=0x%x val=0x%x]\n",R_ACT_DS,M,val); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setES (val) +sys_addr val; +{ + R_ACT_ES = ((sys_addr)M + (val << 4)); +#ifdef MIKE_DEBUG + fprintf (stderr,"setES to 0x%x [M=0x%x val=0x%x]\n",R_ACT_ES,M,val); +#endif MIKE_DEBUG +} + +void soft_a2cpu_setCS (val) +sys_addr val; +{ + R_ACT_CS = (sys_addr)M + (val << 4); +#ifdef MIKE_DEBUG + fprintf (stderr,"setCS to 0x%x [M=0x%x val=0x%x]\n",R_ACT_CS,M,val); +#endif MIKE_DEBUG +} + + + + +void +load_sw_cpu_access_functions () +{ + fprintf (stderr,"[load_sw_cpu_access_functions] init READ/WRITE functions.\n"); + + /* READ functions */ + getAX_func = soft_a2cpu_getAX; + getAH_func = soft_a2cpu_getAH; + getAL_func = soft_a2cpu_getAL; + getBX_func = soft_a2cpu_getBX; + getBH_func = soft_a2cpu_getBH; + getBL_func = soft_a2cpu_getBL; + getCX_func = soft_a2cpu_getCX; + getCH_func = soft_a2cpu_getCH; + getCL_func = soft_a2cpu_getCL; + getDX_func = soft_a2cpu_getDX; + getDH_func = soft_a2cpu_getDH; + getDL_func = soft_a2cpu_getDL; + getSP_func = soft_a2cpu_getSP; + getBP_func = soft_a2cpu_getBP; + getSI_func = soft_a2cpu_getSI; + getDI_func = soft_a2cpu_getDI; + getIP_func = soft_a2cpu_getIP; + getOPA_func = soft_a2cpu_getOPA; /* not used in CCPU */ + getOPB_func = soft_a2cpu_getOPB; /* not used in CCPU */ + getOPR_func = soft_a2cpu_getOPR; /* not used in CCPU */ + getSSD_func = soft_a2cpu_getSSD; /* not used in CCPU */ + getDSD_func = soft_a2cpu_getDSD; /* not used in CCPU */ + getCS_func = soft_a2cpu_getCS; + getDS_func = soft_a2cpu_getDS; + getES_func = soft_a2cpu_getES; + getSS_func = soft_a2cpu_getSS; + getMSW_func = soft_a2cpu_getMSW; + getDF_func = soft_a2cpu_getDF; + getIF_func = soft_a2cpu_getIF; + getTF_func = soft_a2cpu_getTF; + getPF_func = soft_a2cpu_getPF; + getAF_func = soft_a2cpu_getAF; + getSF_func = soft_a2cpu_getSF; + getZF_func = soft_a2cpu_getZF; + getOF_func = soft_a2cpu_getOF; + getCF_func = soft_a2cpu_getCF; + + + /* WRITE functions */ + setAX_func = soft_a2cpu_setAX; + setAH_func = soft_a2cpu_setAH; + setAL_func = soft_a2cpu_setAL; + setBX_func = soft_a2cpu_setBX; + setBH_func = soft_a2cpu_setBH; + setBL_func = soft_a2cpu_setBL; + setCX_func = soft_a2cpu_setCX; + setCH_func = soft_a2cpu_setCH; + setCL_func = soft_a2cpu_setCL; + setDX_func = soft_a2cpu_setDX; + setDH_func = soft_a2cpu_setDH; + setDL_func = soft_a2cpu_setDL; + setSP_func = soft_a2cpu_setSP; + setBP_func = soft_a2cpu_setBP; + setSI_func = soft_a2cpu_setSI; + setDI_func = soft_a2cpu_setDI; + setIP_func = soft_a2cpu_setIP; + setMSW_func = soft_a2cpu_setMSW; + setDF_func = soft_a2cpu_setDF; + setIF_func = soft_a2cpu_setIF; + setTF_func = soft_a2cpu_setTF; + setPF_func = soft_a2cpu_setPF; + setAF_func = soft_a2cpu_setAF; + setSF_func = soft_a2cpu_setSF; + setZF_func = soft_a2cpu_setZF; + setOF_func = soft_a2cpu_setOF; + setCF_func = soft_a2cpu_setCF; + setOPLEN_func = soft_a2cpu_setOPLEN; /* not used in CCPU */ + setOPA_func = soft_a2cpu_setOPA; /* not used in CCPU */ + setOPB_func = soft_a2cpu_setOPB; /* not used in CCPU */ + setOPR_func = soft_a2cpu_setOPR; /* not used in CCPU */ + setSS_func = soft_a2cpu_setSS; + setDS_func = soft_a2cpu_setDS; + setES_func = soft_a2cpu_setES; + setCS_func = soft_a2cpu_setCS; + + /* SW HOST_SIMULATE function */ + host_simulate_func = sw_host_simulate; +} +#endif A2CPU + + +#endif /* CPU_30_STYLE */ + + + + + + + + + + +#ifdef SUN_VA +/* + * ---- SUN_VA HARDWARE SUPPORT ---- + * needed regardless which softCPU is being used. + * ---- ---- + */ + + +extern union SDOS_XTSS *sdos_xtss_ptr; + +/* + * The XTSS fields are stored in i486 format. SWAP the fields + * when accessed from Host-side before writes and after reads. + */ + +#define FLAGS_CF 0x00000001 +#define FLAGS_PF 0x00000004 +#define FLAGS_AF 0x00000010 +#define FLAGS_ZF 0x00000040 +#define FLAGS_SF 0x00000080 +#define FLAGS_TF 0x00000100 +#define FLAGS_IF 0x00000200 +#define FLAGS_DF 0x00000400 +#define FLAGS_OF 0x00000800 +#define FLAGS_IOPL 0x00003000 +#define FLAGS_NT 0x00004000 +#define FLAGS_RF 0x00010000 +#define FLAGS_VM 0x00020000 + + +static word word_reg; +static half_word hword_reg; + +word hard_cpu_getAX () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.ax), &word_reg); + return (word_reg); +} + +half_word hard_cpu_getAH () +{ + sas_load (&(sdos_xtss_ptr->h.ah), &hword_reg); + return (hword_reg); +} + +half_word hard_cpu_getAL () +{ + sas_load (&(sdos_xtss_ptr->h.al), &hword_reg); + return (hword_reg); +} + +word hard_cpu_getBX () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.bx), &word_reg); + return (word_reg); +} + +half_word hard_cpu_getBH () +{ + sas_load (&(sdos_xtss_ptr->h.bh), &hword_reg); + return (hword_reg); +} + +half_word hard_cpu_getBL () +{ + sas_load (&(sdos_xtss_ptr->h.bl), &hword_reg); + return (hword_reg); +} + +word hard_cpu_getCX () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.cx), &word_reg); + return (word_reg); +} + +half_word hard_cpu_getCH () +{ + sas_load (&(sdos_xtss_ptr->h.ch), &hword_reg); + return (hword_reg); +} + +half_word hard_cpu_getCL () +{ + sas_load (&(sdos_xtss_ptr->h.cl), &hword_reg); + return (hword_reg); +} + +word hard_cpu_getDX () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.dx), &word_reg); + return (word_reg); +} + +half_word hard_cpu_getDH () +{ + sas_load (&(sdos_xtss_ptr->h.dh), &hword_reg); + return (hword_reg); +} + +half_word hard_cpu_getDL () +{ + sas_load (&(sdos_xtss_ptr->h.dl), &hword_reg); + return (hword_reg); +} + +word hard_cpu_getSP () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.sp), &word_reg); + return (word_reg); +} + +word hard_cpu_getBP () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.bp), &word_reg); + return (word_reg); +} + +word hard_cpu_getSI () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.si), &word_reg); + return (word_reg); +} + +word hard_cpu_getDI () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.di), &word_reg); + return (word_reg); +} + +word hard_cpu_getIP () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.ip), &word_reg); + return (word_reg); +} + +word hard_cpu_getCS () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.cs), &word_reg); + return (word_reg); +} + +word hard_cpu_getDS () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.ds), &word_reg); + return (word_reg); +} + +word hard_cpu_getES () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.es), &word_reg); + return (word_reg); +} + +word hard_cpu_getSS () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.ss), &word_reg); + return (word_reg); +} + +word hard_cpu_getMSW () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + return (word_reg); +} + +word hard_cpu_getDF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_DF) + return (1); + else + return (0); +} + +word hard_cpu_getIF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_IF) + return (1); + else + return (0); +} + +word hard_cpu_getTF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_TF) + return (1); + else + return (0); +} + +word hard_cpu_getPF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_PF) + return (1); + else + return (0); +} + +word hard_cpu_getAF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_AF) + return (1); + else + return (0); +} + +word hard_cpu_getSF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_SF) + return (1); + else + return (0); +} + +word hard_cpu_getZF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_ZF) + return (1); + else + return (0); +} + +word hard_cpu_getOF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_OF) + return (1); + else + return (0); +} + +word hard_cpu_getCF () +{ + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &word_reg); + if (word_reg & FLAGS_CF) + return (1); + else + return (0); +} + + + + +void hard_cpu_setAX (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.ax), val); +} + +void hard_cpu_setAH (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.ah), val); +} + +void hard_cpu_setAL (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.al), val); +} + +void hard_cpu_setBX (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.bx), val); +} + +void hard_cpu_setBH (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.bh), val); +} + +void hard_cpu_setBL (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.bl), val); +} + +void hard_cpu_setCX (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.cx), val); +} + +void hard_cpu_setCH (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.ch), val); +} + +void hard_cpu_setCL (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.cl), val); +} + +void hard_cpu_setDX (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.dx), val); +} + +void hard_cpu_setDH (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.dh), val); +} + +void hard_cpu_setDL (val) +unsigned int val; +{ + sas_store (&(sdos_xtss_ptr->h.dl), val); +} + +void hard_cpu_setSP (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.sp), val); +} + +void hard_cpu_setBP (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.bp), val); +} + +void hard_cpu_setSI (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.si), val); +} + +void hard_cpu_setDI (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.di), val); +} + +void hard_cpu_setIP (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.ip), val); +} + +void hard_cpu_setCS (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.cs), val); +} + +void hard_cpu_setDS (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.ds), val); +} + +void hard_cpu_setES (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.es), val); +} + +void hard_cpu_setSS (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.ss), val); +} + +void hard_cpu_setMSW (val) +unsigned int val; +{ + sas_storew_swap (&(sdos_xtss_ptr->x.flags), val); +} + +void hard_cpu_setDF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_DF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_DF))); +} + +void hard_cpu_setIF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_IF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_IF))); +} + +void hard_cpu_setTF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_TF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_TF))); +} + +void hard_cpu_setPF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_PF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_PF))); +} + +void hard_cpu_setAF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_AF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_AF))); +} + +void hard_cpu_setSF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_SF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_SF))); +} + +void hard_cpu_setZF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_ZF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_ZF))); +} + +void hard_cpu_setOF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_OF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_OF))); +} + +void hard_cpu_setCF (val) +unsigned int val; +{ +unsigned short temp; + + sas_loadw_swap (&(sdos_xtss_ptr->x.flags), &temp); + if (val) + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp | FLAGS_CF)); + else + sas_storew_swap (&(sdos_xtss_ptr->x.flags), (temp & (~FLAGS_CF))); +} + + + +/* these routines load the CPU access functions pointers for HW and SW. */ +void load_hw_cpu_access_functions () +{ + /* READ functions */ + getAX_func = hard_cpu_getAX; + getAH_func = hard_cpu_getAH; + getAL_func = hard_cpu_getAL; + getBX_func = hard_cpu_getBX; + getBH_func = hard_cpu_getBH; + getBL_func = hard_cpu_getBL; + getCX_func = hard_cpu_getCX; + getCH_func = hard_cpu_getCH; + getCL_func = hard_cpu_getCL; + getDX_func = hard_cpu_getDX; + getDH_func = hard_cpu_getDH; + getDL_func = hard_cpu_getDL; + getSP_func = hard_cpu_getSP; + getBP_func = hard_cpu_getBP; + getSI_func = hard_cpu_getSI; + getDI_func = hard_cpu_getDI; + getIP_func = hard_cpu_getIP; + getCS_func = hard_cpu_getCS; + getDS_func = hard_cpu_getDS; + getES_func = hard_cpu_getES; + getSS_func = hard_cpu_getSS; + getMSW_func = hard_cpu_getMSW; + getDF_func = hard_cpu_getDF; + getIF_func = hard_cpu_getIF; + getTF_func = hard_cpu_getTF; + getPF_func = hard_cpu_getPF; + getAF_func = hard_cpu_getAF; + getSF_func = hard_cpu_getSF; + getZF_func = hard_cpu_getZF; + getOF_func = hard_cpu_getOF; + getCF_func = hard_cpu_getCF; + + /* WRITE functions */ + setAX_func = hard_cpu_setAX; + setAH_func = hard_cpu_setAH; + setAL_func = hard_cpu_setAL; + setBX_func = hard_cpu_setBX; + setBH_func = hard_cpu_setBH; + setBL_func = hard_cpu_setBL; + setCX_func = hard_cpu_setCX; + setCH_func = hard_cpu_setCH; + setCL_func = hard_cpu_setCL; + setDX_func = hard_cpu_setDX; + setDH_func = hard_cpu_setDH; + setDL_func = hard_cpu_setDL; + setSP_func = hard_cpu_setSP; + setBP_func = hard_cpu_setBP; + setSI_func = hard_cpu_setSI; + setDI_func = hard_cpu_setDI; + setIP_func = hard_cpu_setIP; + setCS_func = hard_cpu_setCS; + setDS_func = hard_cpu_setDS; + setES_func = hard_cpu_setES; + setSS_func = hard_cpu_setSS; + setMSW_func = hard_cpu_setMSW; + setDF_func = hard_cpu_setDF; + setIF_func = hard_cpu_setIF; + setTF_func = hard_cpu_setTF; + setPF_func = hard_cpu_setPF; + setAF_func = hard_cpu_setAF; + setSF_func = hard_cpu_setSF; + setZF_func = hard_cpu_setZF; + setOF_func = hard_cpu_setOF; + setCF_func = hard_cpu_setCF; + + /* HW HOST_SIMULATE function */ + host_simulate_func = hw_host_simulate; +} + +#endif SUN_VA diff --git a/private/mvdm/softpc.new/host/src/nt_cpu.c b/private/mvdm/softpc.new/host/src/nt_cpu.c new file mode 100644 index 000000000..7dd303d9d --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_cpu.c @@ -0,0 +1,344 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include "insignia.h" +#include "host_def.h" +/* + * SoftPC Revision 3.0 + * + * Title : NT 3.0 CPU initialization + * + * Description : Initialize the CPU and its registers. + * + * Author : Paul Huckle / Henry Nash + * + * Notes : None + */ + +static char SccsID[]="@(#)sun4_a3cpu.c 1.2 5/24/91 Copyright Insignia Solutions Ltd."; + +#include <stdio.h> +#include <sys/types.h> +#include <malloc.h> +#include "xt.h" +#include CpuH +#include "sas.h" +#include "ios.h" +#include "bios.h" +#include "trace.h" +#include "yoda.h" +#include "debug.h" + +#include "sim32.h" + +#ifdef CPU_40_STYLE +#include "cpu_c.h" +#endif + +GLOBAL quick_event_delays host_delays; +GLOBAL host_addr Start_of_M_area; +GLOBAL IHPE Length_of_M_area; +#ifdef A2CPU +extern void route_on(); +extern void route_on_fragment_no_interrupt_check(); +extern void service_int(); +#endif + +#ifdef I286 +extern word m_s_w; +word protected_mode; +word gdt_limit; +long gdt_base; +word idt_limit; +long idt_base; +#endif + +#define setBASE(base, value) base = (0xff000000 | (value & 0xffffff)) +#define setLIMIT(limit, value) limit = value + +#ifndef PROD + extern RTL_CRITICAL_SECTION IcaLock; +#endif + + + + +/* + Host_start_cpu: This function starts up the cpu emulation if + we are running a software emulation, or if a 486 is present, + starts up this emulation. +*/ +void host_start_cpu() +{ + cpu_simulate (); +} + + +/* + host_simulate: This function starts up the cpu emulation + for recursive CPU calls from the Insignia BIOS +*/ +void host_simulate() +{ + ASSERT(IcaLock.OwningThread != NtCurrentTeb()->ClientId.UniqueThread); + +#ifdef _ALPHA_ + // + // For Alpha AXP, set the arithmetic trap ignore bit since the code + // generators are incapable of generating proper Alpha instructions + // that follow trap shadow rules. + // + // N.B. In this mode all floating point arithmetic traps are ignored. + // Imprecise exceptions are not converted to precise exceptions + // and correct IEEE results are not stored in the destination + // registers of trapping instructions. Only the hardware FPCR + // status bits can be used to determine if any traps occurred. + // + + ((PSW_FPCR)&(NtCurrentTeb()->FpSoftwareStatusRegister))->ArithmeticTrapIgnore = 1; +#endif + + cpu_simulate (); + + ASSERT(IcaLock.OwningThread != NtCurrentTeb()->ClientId.UniqueThread); +} + + +/* + Host_set_hw_int: Cause a hardware interrupt to be generated. For + software cpu this just means setting a bit in cpu_interrupt_map. +*/ +void host_set_hw_int() +{ + cpu_interrupt(CPU_HW_INT, 0); +} + +/* + Host_clear_hw_int: Cause a hardware interrupt to be cleared. For + software cpu this just means clearing a bit in cpu_interrupt_map. + Monitor has it's own version, a3 cpu has it's own (differently named + version). +*/ +#ifndef MONITOR +void host_clear_hw_int() +{ +#ifndef CCPU +#ifdef CPU_40_STYLE + + cpu_clearHwInt(); +#else + IMPORT void a3_cpu_clear_hw_int(); + + a3_cpu_clear_hw_int(); +#endif /* CPU_40_STYLE */ +#endif /* not CCPU */ +} +#endif + + +#ifdef CCPU + +void host_cpu_init() {} + +#endif + +#ifdef A3CPU +void host_cpu_init() +{ + host_delays.com_delay = 10; + host_delays.keyba_delay = 8; + host_delays.timer_delay = 7; + host_delays.fdisk_delay_1 = 100; + host_delays.fdisk_delay_2 = 750; + host_delays.fla_delay = 0; +} + +void setSTATUS(word flags) +{ + setNT((flags >> 14) & 1); + setIOPL((flags >> 12) & 3); + setOF((flags >> 11) & 1); + setDF((flags >> 10) & 1); + setIF((flags >> 9) & 1); + setTF((flags >> 8) & 1); + setSF((flags >> 7) & 1); + setZF((flags >> 6) & 1); + setAF((flags >> 4) & 1); + setPF((flags >> 2) & 1); + setCF(flags & 1); +} + +/* + * Do the Iret for the benefit of the Iret hooks. + * Unwind stack for flags, cs & ip. + * Seems too simple - does the CPU require more cleanup information??? + * or will the unwinding bop sort it out?? + */ +VOID EmulatorEndIretHook() +{ + UNALIGNED word *sptr; + + /* Stack points at CS:IP & Flags of interrupted instruction */ + sptr = (word *)Sim32GetVDMPointer( (getSS() << 16)|getSP(), 2, (UCHAR)(getPE() ? TRUE : FALSE)); + if (sptr) + { + setIP(*sptr++); + setCS(*sptr++); + setSTATUS(*sptr); + setSP(getSP()+6); + } +#ifndef PROD + else + printf("NTVDM extreme badness - can't get stack pointer %x:%x mode:%d\n",getSS(), getSP(), getPE()); +#endif /* PROD */ +} +#endif /* A3CPU */ + +void host_cpu_reset() +{ +} + + +void host_cpu_interrupt() +{ +} + +#ifdef CPU_40_STYLE + +typedef struct NT_CPU_REG { + IU32 *nano_reg; /* where the nano CPU keeps the register */ + IU32 *reg; /* where the light compiler keeps the reg */ + IU32 *saved_reg; /* where currently unused bits are kept */ + IU32 universe_8bit_mask;/* is register in 8-bit form? */ + IU32 universe_16bit_mask;/* is register in 16-bit form? */ +} NT_CPU_REG; + +typedef struct NT_CPU_INFO { + /* Variables for deciding what mode we're in */ + BOOL *in_nano_cpu; /* is the Nano CPU executing? */ + IU32 *universe; /* the mode that the CPU is in */ + + /* General purpose register pointers */ + NT_CPU_REG eax, ebx, ecx, edx, esi, edi, ebp; + + /* Variables for getting SP or ESP. */ + BOOL *stack_is_big; /* is the stack 32-bit? */ + IU32 *nano_esp; /* where the Nano CPU keeps ESP */ + IU8 **host_sp; /* ptr to variable holding stack pointer as a + host address */ + IU8 **ss_base; /* ptr to variables holding base of SS as a + host address */ + IU32 *esp_sanctuary; /* top 16 bits of ESP if we're now using SP */ + + IU32 *eip; + + /* Segment registers. */ + IU16 *cs, *ds, *es, *fs, *gs, *ss; + + IU32 *flags; + + /* CR0, mainly to let us figure out if we're in real or protect mode */ + IU32 *cr0; +} NT_CPU_INFO; + +GLOBAL NT_CPU_INFO nt_cpu_info; + +LOCAL void initNtCpuRegInfo IFN6( + NT_CPU_REG *, info, + IU32 *, nano_reg, + IU32 *, main_reg, + IU32 *, saved_reg, + IU32, in_8bit_form, + IU32, in_16bit_form +) +{ + info->nano_reg = nano_reg; + info->reg = main_reg; + info->saved_reg = saved_reg; + info->universe_8bit_mask = in_8bit_form; + info->universe_16bit_mask = in_16bit_form; +} + + + +GLOBAL void InitNtCpuInfo IFN0() +{ + BOOL *gdp_bool; + + /* Variables for deciding what mode we're in, and hence where the */ + /* register values are kept. */ + + /* Horrible hack, part 1. InNanoCpu is a BOOL, so GLOBAL_InNanoCpu */ + /* is not an l-value, hence we can't take its address. */ +#ifdef ALPHA + nt_cpu_info.in_nano_cpu = (BOOL *) ((IHPE) GDP_PTR + 1223); +#else /* ALPHA */ + nt_cpu_info.in_nano_cpu = (BOOL *) ((IHPE) GDP_PTR + 631); +#endif /* ALPHA */ +#ifndef PROD + gdp_bool = (BOOL *) ((IHPE) GDP_PTR + GdpOffsetFromName("InNanoCpu")); + if (nt_cpu_info.in_nano_cpu != gdp_bool) { + always_trace0("InNanoCpu GDP offset will be wrong in PROD builds"); + } + nt_cpu_info.in_nano_cpu = gdp_bool; +#endif + + nt_cpu_info.universe = &GLOBAL_CurrentUniverse; + + /* Variables needed to get the value SP or ESP. */ + + /* Horrible hack, part 2: as for InNanoCpu, so for stackIsBig. */ +#ifdef ALPHA + nt_cpu_info.stack_is_big = (BOOL *) ((IHPE) GDP_PTR + 7047); +#else /* ALPHA */ + nt_cpu_info.stack_is_big = (BOOL *) ((IHPE) GDP_PTR + 4355); +#endif /* ALPHA */ +#ifndef PROD + gdp_bool = (BOOL *) ((IHPE) GDP_PTR + GdpOffsetFromName("stackIsBig")); + if (nt_cpu_info.stack_is_big != gdp_bool) { + always_trace0("stackIsBig GDP offset will be wrong in PROD builds"); + } + nt_cpu_info.stack_is_big = gdp_bool; +#endif + + nt_cpu_info.nano_esp = &GLOBAL_nanoEsp; + nt_cpu_info.host_sp = &GLOBAL_HSP; + nt_cpu_info.ss_base = &GLOBAL_notionalSsBase; + nt_cpu_info.esp_sanctuary = &GLOBAL_ESPsanctuary; + + /* Pointers to the segment registers. */ + nt_cpu_info.cs = &GLOBAL_CsSel; + nt_cpu_info.ds = &GLOBAL_DsSel; + nt_cpu_info.es = &GLOBAL_EsSel; + nt_cpu_info.fs = &GLOBAL_FsSel; + nt_cpu_info.gs = &GLOBAL_GsSel; + nt_cpu_info.ss = &GLOBAL_SsSel; + + /* EIP & flags, neither of which are likely to be very reliable. */ + nt_cpu_info.eip = &GLOBAL_CleanedRec; + nt_cpu_info.flags = &GLOBAL_EFLAGS; + + nt_cpu_info.cr0 = &GLOBAL_R_CR0; + /* General purpose registers. */ + initNtCpuRegInfo(&nt_cpu_info.eax, &GLOBAL_nanoEax, &GLOBAL_R_EAX, + &GLOBAL_EAXsaved, 1 << ConstraintRAL_LS8, + 1 << ConstraintRAX_LS16); + initNtCpuRegInfo(&nt_cpu_info.ebx, &GLOBAL_nanoEbx, &GLOBAL_R_EBX, + &GLOBAL_EBXsaved, 1 << ConstraintRBL_LS8, + 1 << ConstraintRBX_LS16); + initNtCpuRegInfo(&nt_cpu_info.ecx, &GLOBAL_nanoEcx, &GLOBAL_R_ECX, + &GLOBAL_ECXsaved, 1 << ConstraintRCL_LS8, + 1 << ConstraintRCX_LS16); + initNtCpuRegInfo(&nt_cpu_info.edx, &GLOBAL_nanoEdx, &GLOBAL_R_EDX, + &GLOBAL_EDXsaved, 1 << ConstraintRDL_LS8, + 1 << ConstraintRDX_LS16); + initNtCpuRegInfo(&nt_cpu_info.esi, &GLOBAL_nanoEsi, &GLOBAL_R_ESI, + &GLOBAL_ESIsaved, 0, 1 << ConstraintRSI_LS16); + initNtCpuRegInfo(&nt_cpu_info.edi, &GLOBAL_nanoEdi, &GLOBAL_R_EDI, + &GLOBAL_EDIsaved, 0, 1 << ConstraintRDI_LS16); + initNtCpuRegInfo(&nt_cpu_info.ebp, &GLOBAL_nanoEbp, &GLOBAL_R_EBP, + &GLOBAL_EBPsaved, 0, 1 << ConstraintRBP_LS16); +} + +#endif /* CPU_40_STYLE */ diff --git a/private/mvdm/softpc.new/host/src/nt_det.c b/private/mvdm/softpc.new/host/src/nt_det.c new file mode 100644 index 000000000..398907e66 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_det.c @@ -0,0 +1,1611 @@ +#include <windows.h> +#include "host_def.h" +#include "insignia.h" +#include "vdm.h" + +/* + * ========================================================================== + * Name: nt_det.c + * Author: Jerry Sexton + * Derived From: + * Created On: 6th August 1992 + * Purpose: This module contains the code for the thread which + * detects transitions between windowed and full-screen. + * + * (c)Copyright Insignia Solutions Ltd., 1992. All rights reserved. + * ========================================================================== + * + * Modifications: + * + * Tim August 92. Full-screen and windowed transitions now switch between + * SoftPC video BIOS and host PC video BIOS. + * + */ + +/* + * ========================================================================== + * Other includes + * ========================================================================== + */ +#include <stdlib.h> +#include <ntddvdeo.h> +#include "xt.h" +#include CpuH +#include "gmi.h" +#include "gvi.h" +#include "ios.h" +#include "sas.h" +#include "gfx_upd.h" +#include "egacpu.h" +#include "egaports.h" +#include "egamode.h" +#include "egagraph.h" +#include "video.h" +#include "conapi.h" +#include "host_rrr.h" +#include "debug.h" +#include "error.h" +#include "config.h" +#include "idetect.h" +#include "nt_uis.h" +#include "nt_fulsc.h" +#include "nt_graph.h" +#include "nt_mouse.h" +#include "nt_thred.h" +#include "nt_reset.h" +#include "nt_eoi.h" +#include "nt_event.h" + +/* + * ========================================================================== + * Macros + * ========================================================================== + */ +#define SUSP_FAILURE 0xffffffff + + +// +// A bunch of imports +// +extern DISPLAY_MODE choose_mode[]; + + + +/* + * ========================================================================== + * Global data + * ========================================================================== + */ + +/* Size of video save block. */ +GLOBAL DWORD stateLength; + +/* Video save block pointer. */ +GLOBAL PVIDEO_HARDWARE_STATE_HEADER videoState; +GLOBAL PVOID textState; // Tim Oct 92. + +/* Name of the shared video block. */ +GLOBAL WCHAR_STRING videoSection; +GLOBAL WCHAR_STRING textSection; // Tim Oct 92 + +#ifdef X86GFX +/* Hand-shaking events. */ +GLOBAL HANDLE hStartHardwareEvent; +GLOBAL HANDLE hEndHardwareEvent; +#endif + +/* Flag to stop host_simulates on this thread executing timer tick code. */ +GLOBAL BOOL NoTicks; + +/* +** Tim Oct 92. +** New strategy for windowed graphics updates. A shared buffer with Console +** will remove need to copy the new data over, just pass a rectangle co-ord +** instead. But we still need to copy into the buffer. +*/ +GLOBAL PBYTE *textBuffer; +GLOBAL COORD textBufferSize; // Dimensions of the shared buffer + +GLOBAL BOOL Frozen256Packed = FALSE; // use packed 256 mode paint routine + + + + +/* + * ========================================================================== + * Local data + * ========================================================================== + */ + +/* Variable that indicates if we are in a non-standard VGA mode. */ +LOCAL BOOL inAFunnyMode = FALSE; +LOCAL BOOL ModeSetBatch = FALSE; + +/* Storage for the frozen-window thread handle. */ +LOCAL HANDLE freezeHandle = (HANDLE)0; + + + +/* + * ========================================================================== + * Local function declarations + * ========================================================================== + */ + +#undef LOCAL +#define LOCAL + +LOCAL VOID getCursorInfo(word *, half_word *, half_word *, half_word *); +LOCAL VOID setCursorInfo(word, half_word, half_word, half_word); +LOCAL VOID windowedToFullScreen(SHORT, BOOL); +LOCAL VOID fullScreenToWindowed(VOID); +LOCAL VOID syncHardwareToVGAEmulation(SHORT); +LOCAL VOID syncVGAEmulationToHardware(VOID); +LOCAL BOOL funnyMode(VOID); +LOCAL VOID freezeWindow(VOID); +#ifndef PROD +LOCAL VOID dumpBlock(VOID); +LOCAL VOID dumpPlanes(UTINY *, UTINY *, UTINY *, UTINY *); +#endif /* PROD */ + +/* + * ========================================================================== + * Global functions + * ========================================================================== + */ + +/* +** Tim Oct 92 +** Centralised Console funx. +*/ + +GLOBAL VOID doNullRegister() +{ + DWORD dummylen; + PVOID dummyptr; + COORD dummycoord; + + if( !RegisterConsoleVDM( CONSOLE_UNREGISTER_VDM, + NULL, + NULL, + NULL, + 0, + &dummylen, + &dummyptr, + NULL, + 0, + dummycoord, + &dummyptr + ) + ) + ErrorExit(); +#ifdef X86GFX + sc.Registered = FALSE; +#endif + +} + +/* +******************************************************************* +** initTextSection() +******************************************************************* +*/ +GLOBAL VOID initTextSection(VOID) +{ + DWORD flags; + + // + // VideoSection size is determined by nt video driver + // TextSectionSize is 80 * 50 * BytesPerCharacter + // on risc BytesPerCharacter is 4 (interleaved vga planes) + // on x86 BytesPerCharacter is 2 (only char\attr) + // + textBufferSize.X = 80; + textBufferSize.Y = 50; + +#ifdef X86GFX + /* + * Deallocate the regen area if we start up fullscreen. We have to do this + * before we call RegisterConsoleVDM. Note that's right before the register + * call to make sure no one tries to allocate any memory (eg create a + * section) that could nick bits of the video hole, causing bye-byes. + */ + if (!GetConsoleDisplayMode(&flags)) + ErrorExit(); + savedScreenState = sc.ScreenState = (flags & CONSOLE_FULLSCREEN_HARDWARE) ? + FULLSCREEN : WINDOWED; + sas_store_no_check((int10_seg << 4) + useHostInt10, (half_word)sc.ScreenState); + + if (sc.ScreenState == FULLSCREEN) + LoseRegenMemory(); + +#else + sc.ScreenState = WINDOWED; +#endif + + if( !RegisterConsoleVDM( VDMForWOW ? + CONSOLE_REGISTER_WOW : CONSOLE_REGISTER_VDM, +#ifdef X86GFX + hStartHardwareEvent, + hEndHardwareEvent, +#else + NULL, + NULL, +#endif + NULL, // sectionname no longer used + 0, // sectionnamelen no longer used + &stateLength, + (PVOID *) &videoState, + NULL, // sectionname no longer used + 0, // sectionnamelen no longer used + textBufferSize, + (PVOID *) &textBuffer + ) + ) + ErrorExit(); + +#ifdef X86GFX + /* stateLength can be 0 if fullscreen is disabled in the console */ + if(stateLength) + RtlZeroMemory((BYTE *)videoState, sizeof(VIDEO_HARDWARE_STATE_HEADER)); + sc.Registered = TRUE; +#endif + +} /* end initTextSection() */ + +#ifdef X86GFX + +/*************************************************************************** + * Function: * + * InitDetect * + * * + * Description: * + * Does detection initialisation. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID InitDetect(VOID) +{ + + /* + * Register start and end events with the console. These events are used + * when gaining or losing control of the hardware. + */ + hStartHardwareEvent = CreateEvent((LPSECURITY_ATTRIBUTES) NULL, + FALSE, + FALSE, + NULL); + hEndHardwareEvent = CreateEvent((LPSECURITY_ATTRIBUTES) NULL, + FALSE, + FALSE, + NULL); + if ((hStartHardwareEvent == NULL) || (hEndHardwareEvent == NULL)) + ErrorExit(); + + /* Poll the event to try and get rid of any console queued sets + * This shouldn't be needed (or shouldn't work) but something along + * those lines seems to be happening at the moment. + */ + WaitForSingleObject(hStartHardwareEvent, 0); + + +#ifdef SEPARATE_DETECT_THREAD + /* Go into hand-shaking loop. */ + while (WaitForSingleObject(hStartHardwareEvent, (DWORD) -1) == 0) + DoHandShake(); + + /* We have exited the loop so something funny must have happened. */ + ErrorExit(); +#endif + +} +#ifdef SEPARATE_DETECT_THREAD + +/*************************************************************************** + * Function: * + * CreateDetectThread * + * * + * Description: * + * Creates the detection thread. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID CreateDetectThread(VOID) +{ + DWORD detectID; + HANDLE detectHandle; + + + /* + * If this codes is activated you must close the thread handle + * 28-Feb-1993 Jonle + */ + + + /* Create the detection thread. */ + detectHandle = CreateThread((LPSECURITY_ATTRIBUTES) NULL, + DETECT_THREAD_SIZE, + (LPTHREAD_START_ROUTINE) InitDetect, + (LPVOID) NULL, + (DWORD) 0, + &detectID); + if (detectHandle == -1) + ErrorExit(); +} +#endif /* SEPARATE_DETECT_THREAD */ + +/*************************************************************************** + * Function: * + * DoHandShake * + * * + * Description: * + * Does the hand-shaking with the console server. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID DoHandShake(VOID) +{ + /* + * ICA in's and out's cause a critical section to be entered. As some + * video register out's do ICA out's, we don't want the main thread to be + * suspended while doing ICA in's or out's as this will cause a race + * when the the switching code starts writing to the relevant video + * registers. So wait until the main thread is out of the critical section + * before suspending it. + */ + host_ica_lock(); + + /* + * To stop video memory and registers being updated while we are in the + * middle of hand-shaking, suspend the main thread, which is the one that + * does the updates. + */ + if(SuspendThread(MainThread) == SUSP_FAILURE) + ErrorExit(); + + + if(!VDMForWOW && (SuspendThread(ThreadInfo.EventMgr.Handle)==SUSP_FAILURE)) + ErrorExit(); + + NoTicks = TRUE; + /* + * We have the event telling us to switch so if we are windowed go + * full-screen or if we full-screen go windowed. + */ + if (sc.ScreenState == FULLSCREEN) + { + fullScreenToWindowed(); + } + else + { + windowedToFullScreen(TEXT, BiosModeChange); + + } + + /* Now resume the main thread. */ + NoTicks = FALSE; + + if(!VDMForWOW && ResumeThread(ThreadInfo.EventMgr.Handle) == SUSP_FAILURE) + ErrorExit(); + if(ResumeThread(MainThread) == SUSP_FAILURE) + ErrorExit(); + + /* Leave ICA critical section. */ + host_ica_unlock(); +} + +/*************************************************************************** + * Function: * + * GetDetectEvent * + * * + * Description: * + * Returns the handle to the event which detects a fullscreen switch * + * has occurred. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * hStartHardwareEvent * + * * + ***************************************************************************/ +GLOBAL HANDLE GetDetectEvent(VOID) +{ + return(hStartHardwareEvent); +} + +/* + * ========================================================================== + * Local functions + * ========================================================================== + */ + +/* +*************************************************************************** +** getCursorInfo() - use BIOS funcs to get cursor position and other stuff +*************************************************************************** +** The BIOS could be the SoftPC video BIOS or the host PC's real video BIOS. +** Cursor information needs to be communicated between the two BIOSes when +** a windowed/full-screen transition occurs. +** Tim July 92. +*/ +LOCAL VOID getCursorInfo(word *type, half_word *column, half_word *row, + half_word *page) +{ + + /* Get active page. */ + *page = sas_hw_at_no_check(vd_current_page); + + /* Get cursor position */ + *type = sas_w_at_no_check(VID_CURMOD); + *column = sas_hw_at_no_check(current_cursor_col); + *row = sas_hw_at_no_check(current_cursor_row); +} + +/* +*************************************************************************** +** setCursorInfo() - use BIOS funcs to set cursor position and other stuff +*************************************************************************** +** The BIOS could be the SoftPC video BIOS or the host PC's real video BIOS. +** Cursor information needs to be communicated between the two BIOSes when +** a windowed/full-screen transition occurs. +** Tim July 92. +*/ +LOCAL VOID setCursorInfo(word type, half_word column, half_word row, half_word page) +{ + + /* Set active page. */ + sas_store_no_check(vd_current_page, page); + + /* Set cursor position. */ + sas_storew_no_check(VID_CURMOD, type); + sas_store_no_check(current_cursor_col, column); + sas_store_no_check(current_cursor_row, row); +} + +/*************************************************************************** + * Function: * + * windowedToFullScreen * + * * + * Description: * + * Called when the user or SoftPC requests that the console goes * + * fullscreen. It disables screen updates, synchronises the hardware * + * to SoftPC's video planes and signals the console when it is * + * finished. * + * * + * Parameters: * + * dataType - the type of data stored in the video planes, set to * + * either TEXT or GRAPHICS. * + * biosModeChange - TRUE means call host BIOS to do mode change. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +LOCAL VOID windowedToFullScreen(SHORT dataType, BOOL biosModeChange) +{ + word cursorType; + half_word cursorCol, cursorRow, activePage; + + /* Disable the Idling system when Fullscreen as we cannot detect video + * updates and thus would always idle. + */ + IDLE_ctl(FALSE); + + /* Pass the current state of our VGA emulation to the hardware. */ + syncHardwareToVGAEmulation(dataType); + + /* + ** A variable in K.SYS decides whether + ** to call the host INT 10, or do a video BOP. + ** Set the variable directly and subsequent INT 10's go to host + ** video BIOS. + */ + sas_store_no_check((int10_seg << 4) + useHostInt10, FULLSCREEN); + + /* + ** Tim August 92. Transfer to host video BIOS. + */ + getCursorInfo(&cursorType, &cursorCol, &cursorRow, &activePage); + + setCursorInfo(cursorType, cursorCol, cursorRow, activePage); + + /* + * We only want to call the host bios to do a mode change if the current + * screen switch is due to a bios mode change. + */ + if (biosModeChange) + { + always_trace1("Host BIOS mode change to mode %x.", + sas_hw_at_no_check(vd_video_mode)); + + /* + ** Tim August 92. Transfer to host video BIOS. + */ + getCursorInfo(&cursorType, &cursorCol, &cursorRow, &activePage); + + setCursorInfo(cursorType, cursorCol, cursorRow, activePage); + } +} + +/*************************************************************************** + * Function: * + * syncHardwareToVGAEmulation * + * * + * Description: * + * Copies the contents of SoftPC's video registers and regen buffer * + * to the real hardware on a transition to full-screen. * + * * + * Parameters: * + * dataType - the type of data stored in the video planes, set to * + * either TEXT or GRAPHICS. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +LOCAL VOID syncHardwareToVGAEmulation(SHORT dataType) +{ + ULONG memLoc; + UTINY *regPtr, + *egaPlanePtr, + *regenptr, + *fontptr, + *plane1Ptr, + *plane2Ptr, + *plane3Ptr, + *plane4Ptr; + half_word dummy, + acModeControl, + acIndex, + index, + value, + rgb; + USHORT dacIndex; + BOOL monoMode; + VIDEO_HARDWARE_STATE stateChange; + DWORD bitmapLen = sizeof(VIDEO_HARDWARE_STATE); + DWORD timo; + + /* If we timed out during switch (stress!!), the videoState buffer will + * be removed by console. Check for this before accessing structure and + * take error path down to rest of handshake which will time out and report + * error cleanly. + */ + try { + videoState->ExtendedSequencerOffset = 0; + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "NTVDM:VideoState has valid pointer, but no memory at that address"); + goto syncHandshake; + } + /* + ** If it's a text mode + ** zero the extended fields in the shared saved/restore structure. + ** Kipper, Tim Nov 92. + */ + + /* initialize the video state header if we haven't done it yet. + if it is initialized, leave it alone. + */ + if (videoState->Length == 0) { + videoState->Length = STATELENGTH; + videoState->BasicSequencerOffset = BASICSEQUENCEROFFSET; + videoState->BasicCrtContOffset = BASICCRTCONTOFFSET; + videoState->BasicGraphContOffset = BASICGRAPHCONTOFFSET; + videoState->BasicAttribContOffset = BASICATTRIBCONTOFFSET; + videoState->BasicDacOffset = BASICDACOFFSET; + videoState->BasicLatchesOffset = BASICLATCHESOFFSET; + videoState->PlaneLength = PLANELENGTH; + videoState->Plane1Offset = PLANE1OFFSET; + videoState->Plane2Offset = PLANE2OFFSET; + videoState->Plane3Offset = PLANE3OFFSET; + videoState->Plane4Offset = PLANE4OFFSET; + } + /* Save the current state of the attribute controller index register. */ + inb(EGA_AC_INDEX_DATA, &acIndex); + + /* Enable palette */ + acIndex |= 0x20; + + /* + * Find out if we are running in mono mode as CRTC registers are different + * if we are. + */ + inb(EGA_IPSTAT1_REG, &dummy); + outb(EGA_AC_INDEX_DATA, AC_MODE_CONTROL_REG); + inb(EGA_AC_SECRET, &acModeControl); + monoMode = acModeControl & DISPLAY_TYPE; + + /* Restore the state of the attribute controller index register. */ + inb(EGA_IPSTAT1_REG, &dummy); + outb(EGA_AC_INDEX_DATA, acIndex); + + /* + * Store values to be written to each of the real registers to synchronise + * them to the current state of the registers in the VDD. + */ + if (monoMode) + { + /* Port 0x3b4 */ + inb(0x3b4, (half_word *)&videoState->PortValue[0x4]); + /* Port 0x3b5 */ + inb(0x3b5, (half_word *)&videoState->PortValue[0x5]); + } + + /* Port 0x3c0 */ + videoState->PortValue[0x10] = acIndex; + + /* Port 0x3c1 */ + inb(EGA_AC_SECRET, (half_word *)&videoState->PortValue[0x11]); + + /* Port 0x3c2 */ + inb(VGA_MISC_READ_REG, (half_word *)&videoState->PortValue[0x12]); + + videoState->PortValue[0x13] = 0xff; /* Testing */ + + /* Port 0x3c4 */ + inb(EGA_SEQ_INDEX, (half_word *)&videoState->PortValue[0x14]); + + /* Port 0x3c5 */ + inb(EGA_SEQ_DATA, (half_word *)&videoState->PortValue[0x15]); + + /* Port 0x3c6 */ + inb(VGA_DAC_MASK, (half_word *)&videoState->PortValue[0x16]); + + /* Port 0x3c7 */ + videoState->PortValue[0x17] = get_vga_DAC_rd_addr(); + + /* Port 0x3c8 */ + inb(VGA_DAC_WADDR, (half_word *)&videoState->PortValue[0x18]); + + /* Port 0x3c9 */ + inb(VGA_DAC_DATA, (half_word *)&videoState->PortValue[0x19]); + + /* Port 0x3ce */ + inb(EGA_GC_INDEX, (half_word *)&videoState->PortValue[0x1e]); + + /* Port 0x3cf */ + inb(EGA_GC_DATA, (half_word *)&videoState->PortValue[0x1f]); + + if (!monoMode) + { + /* Port 0x3d4 */ + inb(EGA_CRTC_INDEX, (half_word *)&videoState->PortValue[0x24]); + /* Port 0x3d5 */ + inb(EGA_CRTC_DATA, (half_word *)&videoState->PortValue[0x25]); + } + + /* Port 0x3da */ + inb(VGA_FEAT_READ_REG, (half_word *)&videoState->PortValue[0x2a]); + + /* Store INDEX/DATA etc. register pairs. */ + + /* Initialise `regPtr'. */ + regPtr = GET_OFFSET(BasicSequencerOffset); + + /* Sequencer registers. */ + for (index = 0; index < NUM_SEQ_REGS; index++) + { + outb(EGA_SEQ_INDEX, index); + inb(EGA_SEQ_DATA, &value); + *regPtr++ = value; + } + + /* CRTC registers. */ + regPtr = GET_OFFSET(BasicCrtContOffset); + for (index = 0; index < NUM_CRTC_REGS; index++) + { + outb(EGA_CRTC_INDEX, index); + inb(EGA_CRTC_DATA, &value); + *regPtr++ = value; + } + + /* Graphics controller registers. */ + regPtr = GET_OFFSET(BasicGraphContOffset); + for (index = 0; index < NUM_GC_REGS; index++) + { + outb(EGA_GC_INDEX, index); + inb(EGA_GC_DATA, &value); + *regPtr++ = value; + } + + /* Attribute controller registers. */ + regPtr = GET_OFFSET(BasicAttribContOffset); + for (index = 0; index < NUM_AC_REGS; index++) + { + inb(EGA_IPSTAT1_REG, &dummy); /* Reading 3DA sets 3C0 to index. */ + outb(EGA_AC_INDEX_DATA, index); /* Writing to 3C0 sets it to data. */ + inb(EGA_AC_SECRET, &value); + *regPtr++ = value; + } + inb(EGA_IPSTAT1_REG, &dummy); // re-enable video... + outb(EGA_AC_INDEX_DATA, 0x20); + + /* DAC registers. */ + regPtr = GET_OFFSET(BasicDacOffset); + outb(VGA_DAC_RADDR, (UTINY) 0); + for (dacIndex = 0; dacIndex < NUM_DAC_REGS; dacIndex++) + { + + /* Get 3 values for each port corresponding to red, green and blue. */ + for (rgb = 0; rgb < 3; rgb++) + { + inb(VGA_DAC_DATA, &value); + *regPtr++ = value; + } + } + + /* Latches (which we always set to 0) */ + regPtr = GET_OFFSET(BasicLatchesOffset); + *regPtr++ = 0; + *regPtr++ = 0; + *regPtr++ = 0; + *regPtr++ = 0; + + if (!BiosModeChange) { + /* if this windowed->fullscreen switch was because of video mode change + do not change anything in the code buffer and the font because + the ROM bios set mode will clear them anyway. If "not clear VRAM" + bit was set(int 10h, ah = mode | 0x80), the application will take care + the VRAM refreshing and restoring because if it doesn't the screen + would look funnny as we just swtch mode from TEXT to GRAPHICS and the + video planar chaining conditions are changed. + */ + /* set up pointer to regen memory where the real data lies */ + regenptr = (UTINY *)0xb8000; + + /* and one to the fonts living in the base of the regen area */ + fontptr = (UTINY *)0xa0000; + + plane1Ptr = GET_OFFSET(Plane1Offset); + plane2Ptr = GET_OFFSET(Plane2Offset); + plane3Ptr = GET_OFFSET(Plane3Offset); + plane4Ptr = GET_OFFSET(Plane4Offset); + + +// if we go to fullscreen graphics from text window then the regen contents +// is probably junk??? except when previous save... We can detect this +// transition, so should we save time and just store blank planes??? + + if (dataType == TEXT) + { + // Surprise of the week - the individual planes 0 & 1 actually appear + // to be interleaved with 0's when dumped. Go with this for now, until + // we can suss if that's correct or whether we're not programming up + // the save and restore states properly. + // Probably good on further thoughts as fontplane doesn't show same + // interleave. + // + for (memLoc = 0; memLoc < (0xc0000 - 0xb8000); memLoc++) + { + *plane1Ptr++ = *regenptr++; + *plane1Ptr++ = 0; //char interleave + *plane2Ptr++ = *regenptr++; + *plane2Ptr++ = 0; //attr interleave + } + for (memLoc = 0; memLoc < 0x4000; memLoc++) + { + *plane3Ptr++ = *fontptr++; + *plane3Ptr++ = *fontptr++; + *plane3Ptr++ = *fontptr++; + *plane3Ptr++ = *fontptr++; + } + } + else //only true if restoring previous fullscreen graphics save + { + /* + * Get a copy of the video planes which are inter-leaved in one big + * plane - byte 0 = plane 0, byte 1 = plane 1, byte 2 = plane 2, + * byte 3 = plane 3, byte 4 = plane 0, etc. + */ + /* Set up a pointer to the video planes. */ + egaPlanePtr = EGA_planes; + + for (memLoc = 0; memLoc < videoState->PlaneLength; memLoc++) + { + *plane1Ptr++ = *egaPlanePtr++; + *plane2Ptr++ = *egaPlanePtr++; + *plane3Ptr++ = *egaPlanePtr++; + *plane4Ptr++ = *egaPlanePtr++; + } + } + } + + /* Now pass the data on to the hardware via the console. */ + stateChange.StateHeader = videoState; + stateChange.StateLength = videoState->Plane4Offset + + videoState->PlaneLength; + +#ifndef PROD + dumpBlock(); +#endif + + /* Transfer to this label only occurs if console has removed videostate */ +syncHandshake: + + // do this here to ensure no surprises if get conflict with timer stuff + sc.ScreenState = FULLSCREEN; + + /* make room for the real video memory */ + LoseRegenMemory(); + + if (!SetEvent(hEndHardwareEvent)) // tell console memory's gone + ErrorExit(); + + // wait for console to tell us we can go on. Timeout after 60s + timo = WaitForSingleObject(hStartHardwareEvent, 60000); + + if (timo != 0) // 0 is 'signalled' + { +#ifndef PROD + if (timo == WAIT_TIMEOUT) + printf("NTVDM:Waiting for console to map frame buffer Timed Out\n"); +#endif + SetLastError(ERROR_SERVICE_REQUEST_TIMEOUT); + ErrorExit(); + } + // tell console it can go on. + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + +} + +/*************************************************************************** + * Function: * + * fullScreenToWindowed * + * * + * Description: * + * When hStartHardwareEvent is detected by the timer thread the user * + * wants to go windowed. This function is then called to get the * + * current state of the hardware and send it to the VGA emulation. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ + +int BlockModeChange=0; /* Tim, when set stop nt_set_paint_routine() calling */ + /* TextToGraphics() */ + +LOCAL VOID fullScreenToWindowed(VOID) +{ + + BlockModeChange = 1; /* Temp. disable TextToGraphics calls in the */ + /* following syncVGA... cos it chucks display */ + /* back into full-screen */ + + /* Pass the current state of the hardware to our VGA emulation. */ + syncVGAEmulationToHardware(); + + /* + ** Tim August 92. Switch to SoftPC video BIOS. + */ + BlockModeChange = 0; /* Temp. disable cos it don't work! */ + + /* + ** Set the K.SYS variable which determines whether to use the host + ** video BIOS or do a video BOP. Writing zero means use SoftPC BIOS. + */ + sas_store_no_check((int10_seg << 4) + useHostInt10, (half_word)sc.ScreenState); + + /* Enable the Idling system when return to Windowed */ + /* Only do the following stuff if we are really in windowed mode. + this can happen: (fullscreen ->windowed(frozen) -> fullscreen) */ + if (sc.ScreenState != FULLSCREEN) { + /* + ** Force re-paint of windowed image. + */ + RtlFillMemory(&video_copy[0], 0x7fff, 0xff); + + IDLE_ctl(TRUE); + IDLE_init(); /* and reset triggers */ + + /* + * Clear the old pointer box that has been left befind from + * fullscreen + */ + + CleanUpMousePointer(); + + resetNowCur(); /* reset static vars holding cursor pos. */ + } +} /* end of fullScreenToWindowed() */ + +/*************************************************************************** + * Function: * + * syncVGAEmulationToHardware * + * * + * Description: * + * Copies the real hardware state to SoftPC's video registers and * + * regen buffer on a transition from full-screen to windowed, * + * freezing if we are currently running in a graphics mode. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +LOCAL VOID syncVGAEmulationToHardware(VOID) +{ + ULONG memLoc, + StateFlags; + UTINY *regPtr, + *plane1Ptr, + *plane2Ptr, + *plane3Ptr, + *plane4Ptr, + *RegenPtr, + index, + dummy, + rgb; + USHORT dacIndex; + DWORD bitmapLen = 0, timo; + BOOL changing_to_graphics_mode = FALSE; + + /* Tell console we've got the hardware state. */ + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + + /* Wait for console to unmap memory. */ + timo = WaitForSingleObject(hStartHardwareEvent, 60000); + + if (timo != 0) /* 0 is 'signalled' */ + { +#ifndef PROD + if (timo == WAIT_TIMEOUT) + printf("NTVDM:Waiting for console to unmap frame buffer Timed Out\n"); +#endif + SetLastError(ERROR_SERVICE_REQUEST_TIMEOUT); + ErrorExit(); + } + + /* Put some memory back into the regen area. */ + RegainRegenMemory(); + + /* used to free console here - now must wait as may need to do gfx first */ + + /* Store sequencer values */ + regPtr = GET_OFFSET(BasicSequencerOffset); + for (index = 0; index < NUM_SEQ_REGS; index++) + { + outb(EGA_SEQ_INDEX, index); + outb(EGA_SEQ_DATA, *regPtr++); + } + + /* disable CRTC port locking */ + outb(EGA_CRTC_INDEX, 0x11); + outb(EGA_CRTC_DATA, 0); + + /* Store CRTC values */ + regPtr = GET_OFFSET(BasicCrtContOffset); + for (index = 0; index < NUM_CRTC_REGS; index++) + { + outb(EGA_CRTC_INDEX, index); + outb(EGA_CRTC_DATA, *regPtr++); + } + + + /* Store graphics context values */ + regPtr = GET_OFFSET(BasicGraphContOffset); + for (index = 0; index < NUM_GC_REGS; index++) + { + outb(EGA_GC_INDEX, index); + outb(EGA_GC_DATA, *regPtr++); + } + + + /* Store attribute context values */ + regPtr = GET_OFFSET(BasicAttribContOffset); + inb(EGA_IPSTAT1_REG, &dummy); /* Reading 3DA sets 3C0 to index. */ + for (index = 0; index < NUM_AC_REGS; index++) + { + outb(EGA_AC_INDEX_DATA, index); + outb(EGA_AC_INDEX_DATA, *regPtr++); + } + + + /* Store DAC values. */ + regPtr = GET_OFFSET(BasicDacOffset); + outb(VGA_DAC_WADDR, (UTINY) 0); + for (dacIndex = 0; dacIndex < NUM_DAC_REGS; dacIndex++) + { + for (rgb = 0; rgb < 3; rgb++) + outb(VGA_DAC_DATA, *regPtr++); + } + + + /* Store single value registers. */ + outb( (io_addr)0x3b4, (half_word)videoState->PortValue[0x3b4 - 0x3b0]); //Mono crtc ind + outb( (io_addr)0x3ba, (half_word)videoState->PortValue[0x3ba - 0x3b0]); //Mono Feat + outb( (io_addr)0x3c2, (half_word)videoState->PortValue[0x3c2 - 0x3b0]); //Misc Output + outb( (io_addr)0x3c4, (half_word)videoState->PortValue[0x3c4 - 0x3b0]); //Seq Index + outb( (io_addr)0x3c6, (half_word)videoState->PortValue[0x3c6 - 0x3b0]); //DAC mask + outb( (io_addr)0x3c7, (half_word)videoState->PortValue[0x3c7 - 0x3b0]); //DAC read + outb( (io_addr)0x3c8, (half_word)videoState->PortValue[0x3c8 - 0x3b0]); //DAC write + outb( (io_addr)0x3ce, (half_word)videoState->PortValue[0x3ce - 0x3b0]); //GC Index + outb( (io_addr)0x3d4, (half_word)videoState->PortValue[0x3d4 - 0x3b0]); //CRTC index + + /* Set up pointers to the planes in the video save block. */ + plane1Ptr = GET_OFFSET(Plane1Offset); + plane2Ptr = GET_OFFSET(Plane2Offset); + plane3Ptr = GET_OFFSET(Plane3Offset); + plane4Ptr = GET_OFFSET(Plane4Offset); + +#ifndef PROD + dumpPlanes(plane1Ptr, plane2Ptr, plane3Ptr, plane4Ptr); +#endif /* PROD */ + + /* + * Here is where we need to start making decisions about what mode the above + * has put us into as it effects what we do with the plane data - into regen + * or into ega planes. + */ + StateFlags = videoState->VGAStateFlags; + + ModeSetBatch = FALSE; + + /* + * This actually indicates that the save/restore included all extended + * registers which increases the chances of a mode not being what it + * appears to be from the VGA registers. We need to tighten up the 'funny + * mode' detection. (But not now - too much chance of things). + * + * if (StateFlags & VIDEO_STATE_NON_STANDARD_VGA) + * { + * always_trace0("NTVDM:Non standard VGA - freeze state \n"); + * ModeSetBatch = TRUE; + * } + */ + + if (StateFlags & VIDEO_STATE_UNEMULATED_VGA_STATE) + { + always_trace0("NTVDM:Unemulated VGA State - freeze\n"); + ModeSetBatch = TRUE; + } + + if (StateFlags & VIDEO_STATE_PACKED_CHAIN4_MODE) + { + always_trace0("NTVDM:will need packed 256 colour paint\n"); + Frozen256Packed = TRUE; + } + else + Frozen256Packed = FALSE; + + + if (!ModeSetBatch) + { + (*choose_display_mode)(); + /* screen switching can happen when the BIOS is in the middle + of set mode. The video driver only batches the protected registers(we + will get VIDEO_STATE_UNEMULATED_VGA_STATE, which will set ModeSetBatch). + When we are out of set mode batch and a screen switch happens, + the choose_display_mode would choose a wrong mode(different what the + the bios says) and the parameters setup in base code could be wrong + (we calculate those parameters as it is in TEXT mode while we are in + graphic mode. + + For example, the base code calculate the screen length as: + + screen length = offset_per_line * screen_height_resolution / font_height + + if the bios video mode is graphic mode 4(320 * 200), then + font_height = 2 + screen_height_resolution = 200 + offset_per_line = 80 + the screen_lenght = 80 * 200 / 2 = 8000 bytes which means + the screen has 8000 / 80 = 100 lines!!!! + + Treat it like we are in mode set batch process, so we go to iconized. + */ + if (sc.ModeType == getModeType()) { + + /* Write data to video planes if we are in a graphics mode. */ + if (sc.ModeType == GRAPHICS) + { + + /* + * 'choose_display_mode' calls 'host_set_paint_routine' and in so doing + * sets up 'sc.ModeType'. We now know we have a graphics mode so + * select the frozen paint routines and call 'host_set_paint_routine' + * again to get the required frozen routine. + */ + select_frozen_routines(); + host_set_paint_routine(choose_mode[get_munged_index()], + get_screen_height()); + } + else /* TEXT */ + { + /* Double check not race on graphics mode change */ + + if (sas_hw_at((int10_seg << 4) + changing_mode_flag) == 1) + { + /* In middle of mode change - may actually be graphics any second */ + if ((sas_hw_at(vd_video_mode) > 3) && (sas_hw_at(vd_video_mode) != 7)) + changing_to_graphics_mode = TRUE; + } + /* Now copy the data to the regen buffer. */ + RegenPtr = (UTINY *)0xb8000; + for(memLoc = 0; memLoc < 0x4000; memLoc++) /* 16k of text data. */ + { + *RegenPtr++ = *plane1Ptr++; /* char */ + plane1Ptr++; /* skip interleave */ + *RegenPtr++ = *plane2Ptr++; /* attr */ + plane2Ptr++; /* skip interleave */ + } + + /* Now the font. */ + RegenPtr = (UTINY *)0xa0000; + for(memLoc = 0; memLoc < 0x4000; memLoc++) /* Up to 64k of font data. */ + { + *RegenPtr++ = *plane3Ptr++; + *RegenPtr++ = *plane3Ptr++; + *RegenPtr++ = *plane3Ptr++; + *RegenPtr++ = *plane3Ptr++; + } + } + + /* Re-enable vga attribute palette. */ + inb(EGA_IPSTAT1_REG, &dummy); /* Reading 3DA sets 3C0 to index. */ + outb(EGA_AC_INDEX_DATA, 0x20); + } + else { + ModeSetBatch = TRUE; +#ifndef PROD + OutputDebugString("fullscreen->windowed switching in set mode\n"); +#endif + + } + + } /* modesetbatch */ + /* + * If the state returned by the hardware is one we don't recognise iconify + * the window. If, however, the hardware returns a graphics mode, the + * current image will be displayed. In both cases the app will be frozen + * until the user changes back to fullscreen. + */ + if (ModeSetBatch || (inAFunnyMode = funnyMode()) || (sc.ModeType == GRAPHICS) || changing_to_graphics_mode) + { + +#ifndef PROD + dumpBlock(); +#endif /* PROD */ + + /* if in middle of mode change, don't want to draw screen */ + if (changing_to_graphics_mode) + inAFunnyMode = TRUE; + + /* Must do this before resize function. */ + sc.ScreenState = WINDOWED; + + /* Once we've done this, the VGA emulation is pushed into a graphics + * mode. If we restart windowed, we must ensure it forces itself + * back to a text mode for correct display & so correct screen buffer + * is active. This will be cancelled if we return to a text window. + */ + blocked_in_gfx_mode = TRUE; + + /* + * freezewindow used to run in its own thread. Unfortunately, due to + * console sync problems with video restore on XGA, this did unpleasant + * things to the screen. Thus now this is has become a valid and *Only* + * place in fullscreen switching where console permits us to make + * console API calls. + * I'm sorry, did you say 'Quack', Oh no, I see... + */ + + freezeWindow(); + + /* Tell console we're done. */ + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + + /* We block here until user switches us fullscreen again. */ + WaitForSingleObject(hStartHardwareEvent, INFINITE); + + /* Prevent updates which would cause hang. */ + sc.ScreenState = FULLSCREEN; + + savedScreenState = WINDOWED; /* won't have been changed by timer fn */ + + inAFunnyMode = TRUE; + + /* Put video section back as passed to us as we have not changed it. */ + LoseRegenMemory(); + + /* Tell console memory's gone. */ + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + + /* Wait for console to tell us we can go on. Timeout after 60s */ + timo = WaitForSingleObject(hStartHardwareEvent, 60000); + + if (timo != 0) /* 0 is 'signalled' */ + { +#ifndef PROD + if (timo == WAIT_TIMEOUT) + printf("NTVDM:Waiting for console to map frame buffer Timed Out\n"); +#endif + SetLastError(ERROR_SERVICE_REQUEST_TIMEOUT); + ErrorExit(); + } + + Frozen256Packed = FALSE; + + sas_connect_memory(0xb8000, 0xbffff, SAS_VIDEO); + // tell console server it can go on + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + } + else /* TEXT */ + { + /* Tell console we're done. */ + if (!SetEvent(hEndHardwareEvent)) + ErrorExit(); + + /* Set up screen-state variable. */ + sc.ScreenState = WINDOWED; + + blocked_in_gfx_mode = FALSE; /* save restart mode switch */ +#ifndef PROD + /* Dump out a view of the state block as it might be useful. */ + dumpBlock(); +#endif /* PROD */ + } + + do_new_cursor(); /* sync emulation about cursor state */ +} + +/*************************************************************************** + * Function: * + * funnyMode * + * * + * Description: * + * Detects whether the state of the video hardware returned when * + * switching from fullscreen is one that our VGA emulation * + * understands. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * TRUE if it is a funny state, otherwise FALSE. * + * * + ***************************************************************************/ +LOCAL BOOL funnyMode(VOID) +{ + + /* + * If the screen is of a higher resolution than 640 x 480 we have a + * non-standard VGA mode. + */ + if ((get_bytes_per_line() > 80) || (get_screen_height() > 480)){ + return( FALSE ); /* Tim, don't like it, see what happens other way! */ + /* return(TRUE); */ + } + + /* + * If 'nt_set_paint_routine' was called with 'mode' set to one of the + * "funny" values e.g. TEXT_40_FUN we assume that the mode the hardware + * is currently in is not compatible with the VGA emulation. + */ + if (FunnyPaintMode){ + return(TRUE); + } + + /* We have a standard VGA mode. */ + return(FALSE); +} + +/*************************************************************************** + * Function: * + * freezeWindow * + * * + * Description: * + * This function is the entry point for the temporary thread which * + * does console calls when the main thread is frozen on a fullscreen * + * to windowed transition. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +LOCAL VOID freezeWindow(VOID) +{ + + DWORD Dummy; + + /* Add -FROZEN to the window title. */ + FreezeWinTitle(); + + /* Turn off any active sounds (eg flight simulator engine noise) */ + InitSound(FALSE); + + /* Iconify if we are in a funny mode, otherwise paint the screen. */ + if (ModeSetBatch || inAFunnyMode) + VDMConsoleOperation(VDM_HIDE_WINDOW, &Dummy); + else + { + + + /* Set the screen size. */ + graphicsResize(); + + // + // Remove the Hide Mouse Pointer message from the + // system menu so the user cannot apply this option + // the screen is frozen. + // Andy! + + MouseDetachMenuItem(TRUE); + + /* + * Set up the palette as DAC registers may have changed and we + * won't get any more timer ticks after this one until we + * unfreeze (the palette is not set up until 2 timer ticks after + * 'choose_display_mode' has been called). + */ + set_the_vlt(); + + /* + * Full window graphics paint - relies on paint routines to check + * for memory overflow. + */ + VGLOBS->dirty_flag = (ULONG) 0xffffffff; + (*update_alg.calc_update)(); + } + /* Unblock frozen-window thread creation. */ + freezeHandle = 0; +} + +#ifndef PROD + +/*************************************************************************** + * Function: * + * dumpBlock * + * * + * Description: * + * Dumps the contents of the video state block. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +int dumpit = 0; +LOCAL VOID dumpBlock(VOID) +{ + USHORT i, + dacIndex; + UTINY *regPtr, + index, + rgb; + + if (dumpit == 0) return; + + /* Dump out single value registers. */ + printf("\nSingle value registers:\n"); + for (i = 0; i < 0x30; i++) + printf("\tPort %#x = %#x\n", i, videoState->PortValue[i]); + + /* Dump sequencer values */ + regPtr = GET_OFFSET(BasicSequencerOffset); + printf("Sequencer registers: (addr %#x)\n",regPtr); + for (index = 0; index < NUM_SEQ_REGS; index++) + { + printf(" %#x = %#x\t", index, *regPtr++); + } + printf("\n"); + + /* Dump CRTC values */ + regPtr = GET_OFFSET(BasicCrtContOffset); + printf("CRTC registers: (addr %#x)\n",regPtr); + for (index = 0; index < NUM_CRTC_REGS; index++) + { + printf(" %#x = %#x\t", index, *regPtr++); + } + printf("\n"); + + /* Dump graphics context values */ + regPtr = GET_OFFSET(BasicGraphContOffset); + printf("Graphics context registers: (addr %#x)\n",regPtr); + for (index = 0; index < NUM_GC_REGS; index++) + { + printf(" %#x = %#x\t", index, *regPtr++); + } + printf("\n"); + + /* Dump attribute context values */ + regPtr = GET_OFFSET(BasicAttribContOffset); + printf("Attribute context registers: (addr %#x)\n",regPtr); + for (index = 0; index < NUM_AC_REGS; index++) + { + printf(" %#x = %#x\t", index, *regPtr++); + } + printf("\n"); + + /* Dump DACs. First few only otherwise too slow & console times out! */ + regPtr = GET_OFFSET(BasicDacOffset); + printf("DAC registers:\n"); + for (dacIndex = 0; dacIndex < NUM_DAC_REGS/8; dacIndex++) + { + printf("Ind:%#02x: ", dacIndex); + for (rgb = 0; rgb < 3; rgb++) + { + printf("R:%#02x G:%#02x B:%#02x\t", *regPtr++, *regPtr++, *regPtr++); + } + if ((dacIndex % 4) == 0) printf("\n"); + } +} + +int doPlaneDump = 0; +LOCAL VOID dumpPlanes(UTINY *plane1Ptr, UTINY *plane2Ptr, UTINY *plane3Ptr, + UTINY *plane4Ptr) +{ + HANDLE outFile; + char planeBuffer[256], + *bufptr; + DWORD i, + j, + k, + plane, + nBytes, + bytesWritten; + UTINY *planes[4]; + FAST UTINY *tempPlanePtr; + + if (doPlaneDump) + { + + /* Dump out plane(s). */ + outFile = CreateFile("PLANE", + GENERIC_WRITE, + (DWORD) 0, + (LPSECURITY_ATTRIBUTES) NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + (HANDLE) NULL); + if (outFile == INVALID_HANDLE_VALUE) + ErrorExit(); + planes[0] = plane1Ptr; + planes[1] = plane2Ptr; + planes[2] = plane3Ptr; + planes[3] = plane4Ptr; + for (plane = 0; plane < 4; plane++) + { + tempPlanePtr = planes[plane]; + sprintf(planeBuffer, "Plane %d\n", plane); + strcat(planeBuffer, "-------\n"); + if (!WriteFile(outFile, + planeBuffer, + strlen(planeBuffer), + &bytesWritten, + (LPOVERLAPPED) NULL)) + ErrorExit(); + for (i = 0; i < 0x10000; i += 0x10) + { + sprintf(planeBuffer, "%04x\t", i); + bufptr = planeBuffer + strlen(planeBuffer); + for (j = 0; j < 2; j++) + { + for (k = 0; k < 8; k++) + { + LOCAL char numTab[] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + FAST UTINY temp; + + temp = *tempPlanePtr++; + *bufptr++ = numTab[(temp >> 4) & 0xf]; + *bufptr++ = numTab[temp & 0xf]; + *bufptr++ = ' '; + } + if (j == 0) + { + *bufptr++ = '-'; + *bufptr++ = ' '; + } + } + *bufptr++ = '\n'; + *bufptr++ = '\0'; + nBytes = strlen(planeBuffer); + if (!WriteFile(outFile, + planeBuffer, + nBytes, + &bytesWritten, + (LPOVERLAPPED) NULL)) + ErrorExit(); + } + if (!WriteFile(outFile, + "\n", + 1, + &bytesWritten, + (LPOVERLAPPED) NULL)) + ErrorExit(); + } + CloseHandle(outFile); + } +} + +#endif /* PROD */ +#endif /* X86GFX */ + +#ifdef PLANEDUMPER +extern half_word *vidpl16; +void planedumper() +{ + char filen[50]; + half_word outs[100]; + HANDLE pfh; + int loop, curoff; + char *format = "0123456789abcdef"; + half_word *pl, ch; + + printf("planedumper for plane %d\n", *vidpl16 - 1); + strcpy(filen, "plane "); + filen[5] = '0' + *vidpl16 - 1; + pfh = CreateFile(filen, + GENERIC_WRITE, + (DWORD) 0, + (LPSECURITY_ATTRIBUTES) NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + (HANDLE) NULL); + if (pfh == INVALID_HANDLE_VALUE) + { + printf("Can't create file %s\n", filen); + return; + } + + pl = (half_word *)0xa0000; + + curoff = 0; + for(loop = 0; loop < 64*1024; loop++) + { + ch = *pl++; + outs[curoff++] = *(format + (ch >> 4)); + outs[curoff++] = *(format + (ch & 0xf)); + outs[curoff++] = ' '; + + if (curoff == 78) + { + outs[curoff] = '\n'; + + WriteFile(pfh, outs, 80, &curoff, (LPOVERLAPPED) NULL); + curoff = 0; + } + } + outs[curoff] = '\n'; + + WriteFile(pfh, outs, curoff, &curoff, (LPOVERLAPPED) NULL); + + CloseHandle(pfh); +} +#endif diff --git a/private/mvdm/softpc.new/host/src/nt_ega.c b/private/mvdm/softpc.new/host/src/nt_ega.c new file mode 100644 index 000000000..db83e95f2 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_ega.c @@ -0,0 +1,2144 @@ + +/* + * SoftPC Revision 3.0 + * + * Title : Win32 EGA Graphics Module + * + * Description : + * + * This modules contain the Win32 specific functions required + * to support the EGA emulation. + * + * Author : Dave Bartlett (based on X_ega.c) + * + * Notes : + * + */ + +#include <windows.h> +#include <string.h> +#include <memory.h> + +#include "insignia.h" +#include "host_def.h" + +#include "xt.h" +#include "gvi.h" +#include "gmi.h" +#include "sas.h" +#include "gfx_upd.h" +#include <stdio.h> +#include "trace.h" +#include "debug.h" +#include "egagraph.h" +#include "egacpu.h" +#include "egaports.h" +#include "host_rrr.h" + +#include "conapi.h" +#include "nt_graph.h" +#include "nt_ega.h" +#include "nt_egalt.h" + +#ifdef MONITOR +#include <ntddvdeo.h> +#include "nt_fulsc.h" +#endif /* MONITOR */ + +/* Statics */ + +static unsigned int ega_lo_graph_0_0[256]; +static unsigned int ega_lo_graph_0_1[256]; +static unsigned int ega_lo_graph_0_2[256]; +static unsigned int ega_lo_graph_0_3[256]; +static unsigned int ega_lo_graph_1_0[256]; +static unsigned int ega_lo_graph_1_1[256]; +static unsigned int ega_lo_graph_1_2[256]; +static unsigned int ega_lo_graph_1_3[256]; +static unsigned int ega_lo_graph_2_0[256]; +static unsigned int ega_lo_graph_2_1[256]; +static unsigned int ega_lo_graph_2_2[256]; +static unsigned int ega_lo_graph_2_3[256]; +static unsigned int ega_lo_graph_3_0[256]; +static unsigned int ega_lo_graph_3_1[256]; +static unsigned int ega_lo_graph_3_2[256]; +static unsigned int ega_lo_graph_3_3[256]; + +#ifdef BIGWIN +static unsigned int ega_lo_graph_0_0_big[256]; +static unsigned int ega_lo_graph_0_1_big[256]; +static unsigned int ega_lo_graph_0_2_big[256]; +static unsigned int ega_lo_graph_0_3_big[256]; +static unsigned int ega_lo_graph_1_0_big[256]; +static unsigned int ega_lo_graph_1_1_big[256]; +static unsigned int ega_lo_graph_1_2_big[256]; +static unsigned int ega_lo_graph_1_3_big[256]; +static unsigned int ega_lo_graph_2_0_big[256]; +static unsigned int ega_lo_graph_2_1_big[256]; +static unsigned int ega_lo_graph_2_2_big[256]; +static unsigned int ega_lo_graph_2_3_big[256]; +static unsigned int ega_lo_graph_3_0_big[256]; +static unsigned int ega_lo_graph_3_1_big[256]; +static unsigned int ega_lo_graph_3_2_big[256]; +static unsigned int ega_lo_graph_3_3_big[256]; +static unsigned int ega_lo_graph_4_0_big[256]; +static unsigned int ega_lo_graph_4_1_big[256]; +static unsigned int ega_lo_graph_4_2_big[256]; +static unsigned int ega_lo_graph_4_3_big[256]; +static unsigned int ega_lo_graph_5_0_big[256]; +static unsigned int ega_lo_graph_5_1_big[256]; +static unsigned int ega_lo_graph_5_2_big[256]; +static unsigned int ega_lo_graph_5_3_big[256]; + +static unsigned int ega_lo_graph_0_0_huge[256]; +static unsigned int ega_lo_graph_0_1_huge[256]; +static unsigned int ega_lo_graph_0_2_huge[256]; +static unsigned int ega_lo_graph_0_3_huge[256]; +static unsigned int ega_lo_graph_1_0_huge[256]; +static unsigned int ega_lo_graph_1_1_huge[256]; +static unsigned int ega_lo_graph_1_2_huge[256]; +static unsigned int ega_lo_graph_1_3_huge[256]; +static unsigned int ega_lo_graph_2_0_huge[256]; +static unsigned int ega_lo_graph_2_1_huge[256]; +static unsigned int ega_lo_graph_2_2_huge[256]; +static unsigned int ega_lo_graph_2_3_huge[256]; +static unsigned int ega_lo_graph_3_0_huge[256]; +static unsigned int ega_lo_graph_3_1_huge[256]; +static unsigned int ega_lo_graph_3_2_huge[256]; +static unsigned int ega_lo_graph_3_3_huge[256]; +static unsigned int ega_lo_graph_4_0_huge[256]; +static unsigned int ega_lo_graph_4_1_huge[256]; +static unsigned int ega_lo_graph_4_2_huge[256]; +static unsigned int ega_lo_graph_4_3_huge[256]; +static unsigned int ega_lo_graph_5_0_huge[256]; +static unsigned int ega_lo_graph_5_1_huge[256]; +static unsigned int ega_lo_graph_5_2_huge[256]; +static unsigned int ega_lo_graph_5_3_huge[256]; +static unsigned int ega_lo_graph_6_0_huge[256]; +static unsigned int ega_lo_graph_6_1_huge[256]; +static unsigned int ega_lo_graph_6_2_huge[256]; +static unsigned int ega_lo_graph_6_3_huge[256]; +static unsigned int ega_lo_graph_7_0_huge[256]; +static unsigned int ega_lo_graph_7_1_huge[256]; +static unsigned int ega_lo_graph_7_2_huge[256]; +static unsigned int ega_lo_graph_7_3_huge[256]; +#endif + +static unsigned int ega_med_and_hi_graph_luts[2048]; + +#ifdef BIGWIN +static unsigned int ega_med_and_hi_graph_luts_big[3072]; + +static unsigned int ega_med_and_hi_graph_luts_huge[5120]; +#endif + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Initialise EGA mono low graphics :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_ega_mono_lo_graph() +{ +sub_note_trace0(EGA_HOST_VERBOSE,"nt_init_ega_mono_lo_graph - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Initialise EGA colour low res graphics :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_ega_lo_graph() +{ + static boolean ega_colour_lo_graph_deja_vu = FALSE; + unsigned int i, + byte0, + byte1, + byte2, + byte3, + byte4, + byte5, + byte6, + byte7, + or_of_bytes01, + or_of_bytes23, + or_of_bytes45, + or_of_bytes67; +#ifdef BIGWIN + unsigned int or_of_bytes89, + or_of_bytesab, + or_of_bytescd, + or_of_bytesef; +#endif /* BIGWIN */ + + sub_note_trace0(EGA_HOST_VERBOSE,"nt_init_ega_lo_graph"); + + /* Set up bits-per-pixel for current mode. */ + sc.BitsPerPixel = EGA_BITS_PER_PIXEL; + + /* Initialise look-up table for first call. */ + if( !ega_colour_lo_graph_deja_vu ) + { + for( i = 0; i < 256; i++ ) + { + byte0 = i & 0x1; + byte1 = ( i & 0x2 ) >> 1; + byte2 = ( i & 0x4 ) >> 2; + byte3 = ( i & 0x8 ) >> 3; + byte4 = ( i & 0x10 ) >> 4; + byte5 = ( i & 0x20 ) >> 5; + byte6 = ( i & 0x40 ) >> 6; + byte7 = ( i & 0x80 ) >> 7; + +#ifdef BIGEND + or_of_bytes01 = ( byte1 << 24 ) | ( byte1 << 16 ) | + ( byte0 << 8 ) | byte0; + or_of_bytes23 = ( byte3 << 24 ) | ( byte3 << 16 ) | + ( byte2 << 8 ) | byte2; + or_of_bytes45 = ( byte5 << 24 ) | ( byte5 << 16 ) | + ( byte4 << 8 ) | byte4; + or_of_bytes67 = ( byte7 << 24 ) | ( byte7 << 16 ) | + ( byte6 << 8 ) | byte6; +#endif /* BIGEND */ + +#ifdef LITTLEND + or_of_bytes01 = ( byte0 << 24 ) | ( byte0 << 16 ) | + ( byte1 << 8 ) | byte1; + or_of_bytes23 = ( byte2 << 24 ) | ( byte2 << 16 ) | + ( byte3 << 8 ) | byte3; + or_of_bytes45 = ( byte4 << 24 ) | ( byte4 << 16 ) | + ( byte5<< 8 ) | byte5; + or_of_bytes67 = ( byte6 << 24 ) | ( byte6 << 16 ) | + ( byte7 << 8 ) | byte7; +#endif /* LITTLEND */ + + ega_lo_graph_0_0[i] = or_of_bytes01; + ega_lo_graph_0_1[i] = or_of_bytes01 << 1; + ega_lo_graph_0_2[i] = or_of_bytes01 << 2; + ega_lo_graph_0_3[i] = or_of_bytes01 << 3; + + ega_lo_graph_1_0[i] = or_of_bytes23; + ega_lo_graph_1_1[i] = or_of_bytes23 << 1; + ega_lo_graph_1_2[i] = or_of_bytes23 << 2; + ega_lo_graph_1_3[i] = or_of_bytes23 << 3; + + ega_lo_graph_2_0[i] = or_of_bytes45; + ega_lo_graph_2_1[i] = or_of_bytes45 << 1; + ega_lo_graph_2_2[i] = or_of_bytes45 << 2; + ega_lo_graph_2_3[i] = or_of_bytes45 << 3; + + ega_lo_graph_3_0[i] = or_of_bytes67; + ega_lo_graph_3_1[i] = or_of_bytes67 << 1; + ega_lo_graph_3_2[i] = or_of_bytes67 << 2; + ega_lo_graph_3_3[i] = or_of_bytes67 << 3; + +#ifdef BIGWIN +#ifdef BIGEND + + or_of_bytes01 = ( byte1 << 24 ) | ( byte0 << 16 ) | + ( byte0 << 8 ) | byte0; + or_of_bytes23 = ( byte2 << 24 ) | ( byte2 << 16 ) | + ( byte1 << 8 ) | byte1; + or_of_bytes45 = ( byte3 << 24 ) | ( byte3 << 16 ) | + ( byte3 << 8 ) | byte2; + or_of_bytes67 = ( byte5 << 24 ) | ( byte4 << 16 ) | + ( byte4 << 8 ) | byte4; + or_of_bytes89 = ( byte6 << 24 ) | ( byte6 << 16 ) | + ( byte5 << 8 ) | byte5; + or_of_bytesab = ( byte7 << 24 ) | ( byte7 << 16 ) | + ( byte7 << 8 ) | byte6; + +#endif /* BIGEND */ + +#ifdef LITTLEND + + or_of_bytes01 = ( byte0 << 24 ) | ( byte0 << 16 ) | + ( byte0 << 8 ) | byte1; + or_of_bytes23 = ( byte1 << 24 ) | ( byte1 << 16 ) | + ( byte2 << 8 ) | byte2; + or_of_bytes45 = ( byte2 << 24 ) | ( byte3 << 16 ) | + ( byte3 << 8 ) | byte3; + or_of_bytes67 = ( byte4 << 24 ) | ( byte4 << 16 ) | + ( byte4 << 8 ) | byte5; + or_of_bytes89 = ( byte5 << 24 ) | ( byte5 << 16 ) | + ( byte6 << 8 ) | byte6; + or_of_bytesab = ( byte6 << 24 ) | ( byte7 << 16 ) | + ( byte7 << 8 ) | byte7; + +#endif /* LITTLEND */ + + ega_lo_graph_0_0_big[i] = or_of_bytes01; + ega_lo_graph_0_1_big[i] = or_of_bytes01 << 1; + ega_lo_graph_0_2_big[i] = or_of_bytes01 << 2; + ega_lo_graph_0_3_big[i] = or_of_bytes01 << 3; + + ega_lo_graph_1_0_big[i] = or_of_bytes23; + ega_lo_graph_1_1_big[i] = or_of_bytes23 << 1; + ega_lo_graph_1_2_big[i] = or_of_bytes23 << 2; + ega_lo_graph_1_3_big[i] = or_of_bytes23 << 3; + + ega_lo_graph_2_0_big[i] = or_of_bytes45; + ega_lo_graph_2_1_big[i] = or_of_bytes45 << 1; + ega_lo_graph_2_2_big[i] = or_of_bytes45 << 2; + ega_lo_graph_2_3_big[i] = or_of_bytes45 << 3; + + ega_lo_graph_3_0_big[i] = or_of_bytes67; + ega_lo_graph_3_1_big[i] = or_of_bytes67 << 1; + ega_lo_graph_3_2_big[i] = or_of_bytes67 << 2; + ega_lo_graph_3_3_big[i] = or_of_bytes67 << 3; + + ega_lo_graph_4_0_big[i] = or_of_bytes89; + ega_lo_graph_4_1_big[i] = or_of_bytes89 << 1; + ega_lo_graph_4_2_big[i] = or_of_bytes89 << 2; + ega_lo_graph_4_3_big[i] = or_of_bytes89 << 3; + + ega_lo_graph_5_0_big[i] = or_of_bytesab; + ega_lo_graph_5_1_big[i] = or_of_bytesab << 1; + ega_lo_graph_5_2_big[i] = or_of_bytesab << 2; + ega_lo_graph_5_3_big[i] = or_of_bytesab << 3; + + or_of_bytes01 = ( byte0 << 24 ) | ( byte0 << 16 ) | + ( byte0 << 8 ) | byte0; + or_of_bytes23 = ( byte1 << 24 ) | ( byte1 << 16 ) | + ( byte1 << 8 ) | byte1; + or_of_bytes45 = ( byte2 << 24 ) | ( byte2 << 16 ) | + ( byte2 << 8 ) | byte2; + or_of_bytes67 = ( byte3 << 24 ) | ( byte3 << 16 ) | + ( byte3 << 8 ) | byte3; + or_of_bytes89 = ( byte4 << 24 ) | ( byte4 << 16 ) | + ( byte4 << 8 ) | byte4; + or_of_bytesab = ( byte5 << 24 ) | ( byte5 << 16 ) | + ( byte5 << 8 ) | byte5; + or_of_bytescd = ( byte6 << 24 ) | ( byte6 << 16 ) | + ( byte6 << 8 ) | byte6; + or_of_bytesef = ( byte7 << 24 ) | ( byte7 << 16 ) | + ( byte7 << 8 ) | byte7; + + ega_lo_graph_0_0_huge[i] = or_of_bytes01; + ega_lo_graph_0_1_huge[i] = or_of_bytes01 << 1; + ega_lo_graph_0_2_huge[i] = or_of_bytes01 << 2; + ega_lo_graph_0_3_huge[i] = or_of_bytes01 << 3; + + ega_lo_graph_1_0_huge[i] = or_of_bytes23; + ega_lo_graph_1_1_huge[i] = or_of_bytes23 << 1; + ega_lo_graph_1_2_huge[i] = or_of_bytes23 << 2; + ega_lo_graph_1_3_huge[i] = or_of_bytes23 << 3; + + ega_lo_graph_2_0_huge[i] = or_of_bytes45; + ega_lo_graph_2_1_huge[i] = or_of_bytes45 << 1; + ega_lo_graph_2_2_huge[i] = or_of_bytes45 << 2; + ega_lo_graph_2_3_huge[i] = or_of_bytes45 << 3; + + ega_lo_graph_3_0_huge[i] = or_of_bytes67; + ega_lo_graph_3_1_huge[i] = or_of_bytes67 << 1; + ega_lo_graph_3_2_huge[i] = or_of_bytes67 << 2; + ega_lo_graph_3_3_huge[i] = or_of_bytes67 << 3; + + ega_lo_graph_4_0_huge[i] = or_of_bytes89; + ega_lo_graph_4_1_huge[i] = or_of_bytes89 << 1; + ega_lo_graph_4_2_huge[i] = or_of_bytes89 << 2; + ega_lo_graph_4_3_huge[i] = or_of_bytes89 << 3; + + ega_lo_graph_5_0_huge[i] = or_of_bytesab; + ega_lo_graph_5_1_huge[i] = or_of_bytesab << 1; + ega_lo_graph_5_2_huge[i] = or_of_bytesab << 2; + ega_lo_graph_5_3_huge[i] = or_of_bytesab << 3; + + ega_lo_graph_6_0_huge[i] = or_of_bytescd; + ega_lo_graph_6_1_huge[i] = or_of_bytescd << 1; + ega_lo_graph_6_2_huge[i] = or_of_bytescd << 2; + ega_lo_graph_6_3_huge[i] = or_of_bytescd << 3; + + ega_lo_graph_7_0_huge[i] = or_of_bytesef; + ega_lo_graph_7_1_huge[i] = or_of_bytesef << 1; + ega_lo_graph_7_2_huge[i] = or_of_bytesef << 2; + ega_lo_graph_7_3_huge[i] = or_of_bytesef << 3; + +#endif /* BIGWIN */ + } + + ega_colour_lo_graph_deja_vu = TRUE; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::: Initialise EGA med/hi res graphics :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_ega_med_and_hi_graph_luts() +{ + static boolean init_ega_med_and_hi_graph_luts_deja_vu = FALSE; + unsigned int i, + byte0, + byte1, + byte2, + byte3, + byte4, + byte5, + byte6, + byte7, + or_of_bytes1, + or_of_bytes2, + *lut0_ptr = &ega_med_and_hi_graph_luts[0], + *lut1_ptr = lut0_ptr + LUT_OFFSET, + *lut2_ptr = lut1_ptr + LUT_OFFSET, + *lut3_ptr = lut2_ptr + LUT_OFFSET; +#ifdef BIGWIN + unsigned int or_of_bytes3, + or_of_bytes4, + *lut0_big_ptr = &ega_med_and_hi_graph_luts_big[0], + *lut1_big_ptr = lut0_big_ptr + BIG_LUT_OFFSET, + *lut2_big_ptr = lut1_big_ptr + BIG_LUT_OFFSET, + *lut3_big_ptr = lut2_big_ptr + BIG_LUT_OFFSET, + *lut0_huge_ptr = &ega_med_and_hi_graph_luts_huge[0], + *lut1_huge_ptr = lut0_huge_ptr + HUGE_LUT_OFFSET, + *lut2_huge_ptr = lut1_huge_ptr + HUGE_LUT_OFFSET, + *lut3_huge_ptr = lut2_huge_ptr + HUGE_LUT_OFFSET, + *lut4_huge_ptr = lut3_huge_ptr + HUGE_LUT_OFFSET; +#endif /* BIGWIN */ + + sub_note_trace0(EGA_HOST_VERBOSE, "nt_init_ega_med_and_hi_graph_luts"); + + if (init_ega_med_and_hi_graph_luts_deja_vu) + return; + + init_ega_med_and_hi_graph_luts_deja_vu = TRUE; + + for(i = 0; i < 256; i++) + { + byte0 = i & 0x1; + byte1 = (i & 0x2) >> 1; + byte2 = (i & 0x4) >> 2; + byte3 = (i & 0x8) >> 3; + byte4 = (i & 0x10) >> 4; + byte5 = (i & 0x20) >> 5; + byte6 = (i & 0x40) >> 6; + byte7 = (i & 0x80) >> 7; + +#ifdef BIGEND + + or_of_bytes1 = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; + or_of_bytes2 = (byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte4; + +#endif /* BIGEND */ + +#ifdef LITTLEND + + or_of_bytes1 = (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3; + or_of_bytes2 = (byte4 << 24) | (byte5 << 16) | (byte6 << 8) | byte7; + +#endif /* LITTLEND */ + + + lut0_ptr[2*i] = or_of_bytes2; + lut0_ptr[2*i+1] = or_of_bytes1; + lut1_ptr[2*i] = or_of_bytes2 << 1; + lut1_ptr[2*i+1] = or_of_bytes1 << 1; + lut2_ptr[2*i] = or_of_bytes2 << 2; + lut2_ptr[2*i+1] = or_of_bytes1 << 2; + lut3_ptr[2*i] = or_of_bytes2 << 3; + lut3_ptr[2*i+1] = or_of_bytes1 << 3; + +#ifdef BIGWIN +#ifdef BIGEND + + or_of_bytes1 = (byte2 << 24) | (byte1 << 16) | (byte0 << 8) | byte0; + or_of_bytes2 = (byte4 << 24) | (byte4 << 16) | (byte3 << 8) | byte2; + or_of_bytes3 = (byte7 << 24) | (byte6 << 16) | (byte6 << 8) | byte5; + +#endif /*BIGEND */ + +#ifdef LITTLEND + + or_of_bytes1 = (byte0 << 24) | (byte0 << 16) | (byte1 << 8) | byte2; + or_of_bytes2 = (byte2 << 24) | (byte3 << 16) | (byte4 << 8) | byte4; + or_of_bytes3 = (byte5 << 24) | (byte6 << 16) | (byte6 << 8) | byte7; + +#endif /* LITTLEND */ + + lut0_big_ptr[3*i] = or_of_bytes3; + lut0_big_ptr[3*i+1] = or_of_bytes2; + lut0_big_ptr[3*i+2] = or_of_bytes1; + lut1_big_ptr[3*i] = or_of_bytes3 << 1; + lut1_big_ptr[3*i+1] = or_of_bytes2 << 1; + lut1_big_ptr[3*i+2] = or_of_bytes1 << 1; + lut2_big_ptr[3*i] = or_of_bytes3 << 2; + lut2_big_ptr[3*i+1] = or_of_bytes2 << 2; + lut2_big_ptr[3*i+2] = or_of_bytes1 << 2; + lut3_big_ptr[3*i] = or_of_bytes3 << 3; + lut3_big_ptr[3*i+1] = or_of_bytes2 << 3; + lut3_big_ptr[3*i+2] = or_of_bytes1 << 3; + +#ifdef BIGEND + + or_of_bytes1 = (byte1 << 24) | (byte1 << 16) | (byte0 << 8) | byte0; + or_of_bytes2 = (byte3 << 24) | (byte3 << 16) | (byte2 << 8) | byte2; + or_of_bytes3 = (byte5 << 24) | (byte5 << 16) | (byte4 << 8) | byte4; + or_of_bytes4 = (byte7 << 24) | (byte7 << 16) | (byte6 << 8) | byte6; + +#endif /* BIGEND */ + +#ifdef LITTLEND + + or_of_bytes1 = (byte0 << 24) | (byte0 << 16) | (byte1 << 8) | byte1; + or_of_bytes2 = (byte2 << 24) | (byte2 << 16) | (byte3 << 8) | byte3; + or_of_bytes3 = (byte4 << 24) | (byte4 << 16) | (byte5 << 8) | byte5; + or_of_bytes4 = (byte6 << 24) | (byte6 << 16) | (byte7 << 8) | byte7; + +#endif /* LITTLEND */ + + lut0_huge_ptr[4*i] = or_of_bytes4; + lut0_huge_ptr[4*i+1] = or_of_bytes3; + lut0_huge_ptr[4*i+2] = or_of_bytes2; + lut0_huge_ptr[4*i+3] = or_of_bytes1; + lut1_huge_ptr[4*i] = or_of_bytes4 << 1; + lut1_huge_ptr[4*i+1] = or_of_bytes3 << 1; + lut1_huge_ptr[4*i+2] = or_of_bytes2 << 1; + lut1_huge_ptr[4*i+3] = or_of_bytes1 << 1; + lut2_huge_ptr[4*i] = or_of_bytes4 << 2; + lut2_huge_ptr[4*i+1] = or_of_bytes3 << 2; + lut2_huge_ptr[4*i+2] = or_of_bytes2 << 2; + lut2_huge_ptr[4*i+3] = or_of_bytes1 << 2; + lut3_huge_ptr[4*i] = or_of_bytes4 << 3; + lut3_huge_ptr[4*i+1] = or_of_bytes3 << 3; + lut3_huge_ptr[4*i+2] = or_of_bytes2 << 3; + lut3_huge_ptr[4*i+3] = or_of_bytes1 << 3; + lut4_huge_ptr[4*i] = or_of_bytes4 << 4; + lut4_huge_ptr[4*i+1] = or_of_bytes3 << 4; + lut4_huge_ptr[4*i+2] = or_of_bytes2 << 4; + lut4_huge_ptr[4*i+3] = or_of_bytes1 << 4; +#endif /* BIGWIN */ + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::: Initialise EGA med res graphics ::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_ega_med_graph() +{ + sub_note_trace0(EGA_HOST_VERBOSE, "nt_init_ega_med_graph"); + + /* Set up the number of bits per pixel for this mode. */ + sc.BitsPerPixel = EGA_BITS_PER_PIXEL; + + /* Initialise the medium- and high-resolution look-up tables. */ + nt_init_ega_med_and_hi_graph_luts(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Initialise hi res graphics :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_ega_hi_graph() +{ + + sub_note_trace0(EGA_HOST_VERBOSE, "nt_init_ega_hi_graph"); + + /* Set up the number of bits per pixel for this mode. */ + sc.BitsPerPixel = EGA_BITS_PER_PIXEL; + + /* Initialise the medium- and high-resolution look-up tables. */ + nt_init_ega_med_and_hi_graph_luts(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Paint EGA screen with user defined font ::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void ega_nt_text_with_user_font(int offset,int cur_xpos,int cur_ypos,int len) +{ + int a = offset = cur_xpos = cur_ypos = len; + +sub_note_trace0(EGA_HOST_VERBOSE,"ega_nt_text_with_user_font - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Paint EGA screen with user defined font ::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void ega_nt_big_text_with_user_font(int offset, int cur_xpos, + int cur_ypos, int len) +{ + int a = offset = cur_xpos = cur_ypos = len; + + sub_note_trace0(EGA_HOST_VERBOSE, + "ega_nt_big_text_with_user_font - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Paint screen with EGA text ::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint win32 screen (MODE 13: PC 320x200. SoftPC 640x400) ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_lo_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + unsigned int *p0, + *ref_p0, + *dest_ptr, + *save_dest_ptr, + data0, + data1, + data2, + data3; + int local_width, + local_height, + longs_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_lo_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>40 ){ + assert2( NO, "VDM: nt_ega_lo_graph_std() w=%d h=%d", width, height ); + return; + } + + + /* Get source and destination data pointers. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + save_dest_ptr = (unsigned int *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * longs_per_scanline + + (screen_x >> 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* + * Build up DIB: 4 consecutive bytes in video memory correspond to 8 + * pixels, the first byte containing plane 0 bits, the second byte plane 1 + * and so on. This mode is low resolution so each pixel in video memory + * becomes a block of 4 pixels on the PC screen. + * The DIB contains the bottom line of pixels first, then second bottom + * so on. + */ + local_height = height; + do + { + p0 = ref_p0; + local_width = width; + dest_ptr = save_dest_ptr; + + do + { + data0 = *p0++; + data3 = HIBYTE(HIWORD(data0)); + data2 = LOBYTE(HIWORD(data0)); + data1 = HIBYTE(LOWORD(data0)); + data0 = LOBYTE(LOWORD(data0)); + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_3_0[data0] | ega_lo_graph_3_1[data1] + | ega_lo_graph_3_2[data2] | ega_lo_graph_3_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_2_0[data0] | ega_lo_graph_2_1[data1] + | ega_lo_graph_2_2[data2] | ega_lo_graph_2_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_1_0[data0] | ega_lo_graph_1_1[data1] + | ega_lo_graph_1_2[data2] | ega_lo_graph_1_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_0_0[data0] | ega_lo_graph_0_1[data1] + | ega_lo_graph_0_2[data2] | ega_lo_graph_0_3[data3]; + dest_ptr++; + + } + while(--local_width); + + save_dest_ptr += 2 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 1; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 4) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint win32 screen (MODE 13: PC 320x200. SoftPC 960x600) ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_lo_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + unsigned int *p0, + *ref_p0, + *dest_ptr, + *save_dest_ptr, + data0, + data1, + data2, + data3; + int local_width, + local_height, + longs_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_lo_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>40 ){ + assert2( NO, "VDM: nt_ega_lo_graph_big() w=%d h=%d", width, height ); + return; + } + + + /* Get source and destination data pointers. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + save_dest_ptr = (unsigned int *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * longs_per_scanline + + SCALE(screen_x >> 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up DIB. */ + local_height = height; + do + { + p0 = ref_p0; + local_width = width; + dest_ptr = save_dest_ptr; + + do + { + data0 = *p0++; + data3 = HIBYTE(HIWORD(data0)); + data2 = LOBYTE(HIWORD(data0)); + data1 = HIBYTE(LOWORD(data0)); + data0 = LOBYTE(LOWORD(data0)); + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_5_0_big[data0] + | ega_lo_graph_5_1_big[data1] + | ega_lo_graph_5_2_big[data2] + | ega_lo_graph_5_3_big[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_4_0_big[data0] + | ega_lo_graph_4_1_big[data1] + | ega_lo_graph_4_2_big[data2] + | ega_lo_graph_4_3_big[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_3_0_big[data0] + | ega_lo_graph_3_1_big[data1] + | ega_lo_graph_3_2_big[data2] + | ega_lo_graph_3_3_big[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_2_0_big[data0] + | ega_lo_graph_2_1_big[data1] + | ega_lo_graph_2_2_big[data2] + | ega_lo_graph_2_3_big[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_1_0_big[data0] + | ega_lo_graph_1_1_big[data1] + | ega_lo_graph_1_2_big[data2] + | ega_lo_graph_1_3_big[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2*longs_per_scanline) + = *dest_ptr + = ega_lo_graph_0_0_big[data0] + | ega_lo_graph_0_1_big[data1] + | ega_lo_graph_0_2_big[data2] + | ega_lo_graph_0_3_big[data3]; + dest_ptr++; + + } + while( --local_width ); + + save_dest_ptr += 3 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 1); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 4) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + /* Display the DIB. */ + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint win32 screen (MODE 13: PC 320x200. SoftPC 1280x800) ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_lo_graph_huge(int offset, int screen_x, int screen_y, + int width, int height ) +{ +#ifdef BIGWIN + unsigned int *p0, + *ref_p0, + *dest_ptr, + *save_dest_ptr, + data0, + data1, + data2, + data3; + int local_width, + local_height, + longs_per_scanline; + SMALL_RECT rect; + + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_lo_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>40 ){ + assert2( NO, "VDM: nt_ega_lo_graph_huge() w=%d h=%d", width, height ); + return; + } + + + /* Get source and destination data pointers. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + save_dest_ptr = (unsigned int *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * longs_per_scanline + + SCALE(screen_x >> 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up DIB. */ + local_height = height; + do + { + p0 = ref_p0; + local_width = width; + dest_ptr = save_dest_ptr; + + do + { + data0 = *p0++; + data3 = HIBYTE(HIWORD(data0)); + data2 = LOBYTE(HIWORD(data0)); + data1 = HIBYTE(LOWORD(data0)); + data0 = LOBYTE(LOWORD(data0)); + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_7_0_huge[data0] + | ega_lo_graph_7_1_huge[data1] + | ega_lo_graph_7_2_huge[data2] + | ega_lo_graph_7_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_6_0_huge[data0] + | ega_lo_graph_6_1_huge[data1] + | ega_lo_graph_6_2_huge[data2] + | ega_lo_graph_6_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_5_0_huge[data0] + | ega_lo_graph_5_1_huge[data1] + | ega_lo_graph_5_2_huge[data2] + | ega_lo_graph_5_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_4_0_huge[data0] + | ega_lo_graph_4_1_huge[data1] + | ega_lo_graph_4_2_huge[data2] + | ega_lo_graph_4_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_3_0_huge[data0] + | ega_lo_graph_3_1_huge[data1] + | ega_lo_graph_3_2_huge[data2] + | ega_lo_graph_3_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_2_0_huge[data0] + | ega_lo_graph_2_1_huge[data1] + | ega_lo_graph_2_2_huge[data2] + | ega_lo_graph_2_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_1_0_huge[data0] + | ega_lo_graph_1_1_huge[data1] + | ega_lo_graph_1_2_huge[data2] + | ega_lo_graph_1_3_huge[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *(dest_ptr + 2 * longs_per_scanline) + = *(dest_ptr + 3 * longs_per_scanline) + = *dest_ptr + = ega_lo_graph_0_0_huge[data0] + | ega_lo_graph_0_1_huge[data1] + | ega_lo_graph_0_2_huge[data2] + | ega_lo_graph_0_3_huge[data3]; + dest_ptr++; + + } + while( --local_width ); + + save_dest_ptr += 4 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 1); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 4) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + /* Display the DIB. */ + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen (MODE 14: PC 640x200. SoftPC 640x400) :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_med_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_med_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>80 ){ + assert2( NO, "VDM: nt_ega_med_graph_std() w=%d h=%d", width, height ); + return; + } + + + /* + * Build up device-independent bitmap: one PC pixel is represented by two + * host pixels, one above the other. + */ + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + local_height = height; + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * bytes_per_scanline + + screen_x; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up the bitmap. */ + do + { + ega_colour_hi_munge((unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts, + TWO_SCANLINES, + bytes_per_scanline); + p0 += get_offset_per_line(); + dest_ptr += TWO_SCANLINES * bytes_per_scanline; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen MODE 14: PC 640x200. SoftPC 960x600 :::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_med_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_med_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>80 ){ + assert2( NO, "VDM: nt_ega_med_graph_big() w=%d h=%d", width, height ); + return; + } + + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + local_height = height; + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * bytes_per_scanline + + SCALE(screen_x); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + ega_colour_hi_munge_big( (unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts_big, + THREE_SCANLINES, + bytes_per_scanline); + p0 += get_offset_per_line(); + dest_ptr += THREE_SCANLINES * bytes_per_scanline; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen MODE 14: PC 640x200. SoftPC 1280x800 :::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_med_graph_huge(int offset, int screen_x, int screen_y, + int width, int height ) +{ +#ifdef BIGWIN + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_med_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>200 || width>80 ){ + assert2( NO, "VDM: nt_ega_med_graph_huge() w=%d h=%d", width, height ); + return; + } + + + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + local_height = height; + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * bytes_per_scanline + + SCALE(screen_x); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + ega_colour_hi_munge_huge( (unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts_huge, + FOUR_SCANLINES, + bytes_per_scanline); + p0 += get_offset_per_line(); + dest_ptr += FOUR_SCANLINES * bytes_per_scanline; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen (MODE 16: PC 640x350. SoftPC 960x375) :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_hi_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>480 || width>80 ){ + assert2( NO, "VDM: nt_ega_hi_graph_std() w=%d h=%d", width, height ); + return; + } + + /* Build up the device independent bitmap. */ + p0 = ( unsigned int *) get_regen_ptr( 0, offset << 2 ); + local_height = height; + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bytes_per_scanline + + screen_x; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + ega_colour_hi_munge((unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts, + ONE_SCANLINE, + 0); + p0 += get_offset_per_line(); + dest_ptr += bytes_per_scanline; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen (MODE 16: PC 640x350. SoftPC 960x525) :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + register int local_screen_y; + register int scale_width_in_bits; + int bytes_per_scanline; + BOOL two_lines; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_hi_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>480 || width>80 ){ + assert2( NO, "VDM: nt_ega_hi_graph_big() w=%d h=%d", width, height ); + return; + } + + + /* Get pointer to video memory. */ + p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + + /* + * Get pointer into bitmap, which alternates 2 lines and 1 line so that, + * memory line 0 -> bitmap 0, + * 1 -> 2, + * 2 -> 3, + * 3 -> 5, + * 4 -> 6 etc. + * hence the local_screen_y assignment. + */ + local_screen_y = SCALE(screen_y + 1) - 1; + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + local_screen_y * bytes_per_scanline + + SCALE(screen_x); + + /* + * 2 lines are output to the SoftPC screen if this is an odd line, 1 line + * if it is even. + */ + two_lines = screen_y & 1 ? FALSE : TRUE; + + /* + * One bit in video memory planes corresponds to one pixel. Each pixel + * is represented by one byte in the bitmap. Two pixels are scaled to + * three in the bitmap. `scale_width_in_bits' is the number of bytes that + * will be output to a bitmap line. + */ + scale_width_in_bits = SCALE(width << 3); + + /* Storage for actual number of lines in bitmap. */ + local_height = 0; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + ega_colour_hi_munge_big((unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts_big, + ONE_SCANLINE, + 0); + + /* one line done, alternate ones have to be doubled */ + if(two_lines) + { + memcpy(dest_ptr + bytes_per_scanline, + dest_ptr, + scale_width_in_bits); + dest_ptr += 2 * bytes_per_scanline; + local_height += 2; + } + else + { + dest_ptr += bytes_per_scanline; + local_height++; + } + two_lines = !two_lines; + + p0 += get_offset_per_line(); + } + while(--height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = local_screen_y; + rect.Right = rect.Left + scale_width_in_bits - 1; + rect.Bottom = rect.Top + local_height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen (MODE 16: PC 640x350. SoftPC 1280x700) :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + register unsigned int *p0; + register char *dest_ptr; + register int local_height; + int bytes_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_hi_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>480 || width>80 ){ + assert2( NO, "VDM: nt_ega_hi_graph_huge() w=%d h=%d", width, height ); + return; + } + + + p0 = (unsigned int *) get_regen_ptr(0, offset << 2); + local_height = height; + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + dest_ptr = (char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y) * bytes_per_scanline + + SCALE(screen_x); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + ega_colour_hi_munge_huge((unsigned char *) p0, + width, + (unsigned int *) dest_ptr, + ega_med_and_hi_graph_luts_huge, + ONE_SCANLINE, + 0); + + p0 += get_offset_per_line(); + memcpy(dest_ptr + bytes_per_scanline, dest_ptr, SCALE(width << 3)); + dest_ptr += 2 * bytes_per_scanline; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint Win32 screen (MODE : EGA mono low res graphics) ::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_lo_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_lo_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::: Paint function for EGA mono low res graphics on big screen ::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_lo_graph_big(int offset, int screen_x, int screen_y, + int width, int height ) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_lo_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::: Paint function for EGA mono low res graphics on huge screen :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_lo_graph_huge(int offset, int screen_x, int screen_y, + int width, int height ) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_lo_graph_huge off=%d x=%d y=%d width=%d h=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height ); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::: Paint function for EGA mono med res graphics :::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_med_graph_std(int offset, int screen_x, int screen_y, + int width, int height) + +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_med_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::: Paint function for EGA mono med res graphics on big screen ::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_med_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_med_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::: Paint function for EGA mono med res graphics on huge screen :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_med_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_med_graph_huge off=%d x=%d y=%d width=%d h=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::: Paint function for EGA mono hi res graphics :::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_hi_graph_std_byte(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_hi_graph_std_byte off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::: Paint function for EGA mono hi res graphics (long):::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_hi_graph_std_long(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_hi_graph_std_long off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::: Paint function for EGA mono hi res graphics :::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_hi_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Paint function for EGA mono hi res graphics on big screen::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_hi_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Paint function for EGA mono hi res graphics on huge screen:::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_mono_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height ) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_mono_hi_graph_huge off=%d x=%d y=%d width=%d h=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +#ifdef MONITOR +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint frozen screen (MODE 13: PC 320x200. SoftPC 640x400) :::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_lo_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + UTINY *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + ULONG *dest_ptr, + *save_dest_ptr, + mem_loc, + data0, + data1, + data2, + data3, + local_width, + local_height, + longs_per_scanline, + bpl = get_bytes_per_line(), + mem_x = screen_x >> 3, + max_width = sc.PC_W_Width >> 4, + max_height = sc.PC_W_Height >> 1; + SMALL_RECT rect; + BOOL fMutexTaken = FALSE; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_lo_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((mem_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_ega_lo_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (mem_x + width > max_width) + width = max_width - mem_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* Get source and destination data pointers. */ + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + save_dest_ptr = (unsigned int *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * longs_per_scanline + + (screen_x >> 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = TRUE; + + /* + * Build up DIB: 4 consecutive bytes in video memory correspond to 8 + * pixels the first byte containing plane 0, the second byte plane 1 + * and so on. This mode is low resolution so each pixel in video memory + * becomes a block of 4 pixels on the PC screen. + * The DIB contains the bottom line of pixels first, then second bottom + * so on. + */ + local_height = height; + do + { + local_width = width; + dest_ptr = save_dest_ptr; + mem_loc = offset; + do + { + data0 = *(plane1_ptr + mem_loc); + data1 = *(plane2_ptr + mem_loc); + data2 = *(plane3_ptr + mem_loc); + data3 = *(plane4_ptr + mem_loc); + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_3_0[data0] | ega_lo_graph_3_1[data1] + | ega_lo_graph_3_2[data2] | ega_lo_graph_3_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_2_0[data0] | ega_lo_graph_2_1[data1] + | ega_lo_graph_2_2[data2] | ega_lo_graph_2_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_1_0[data0] | ega_lo_graph_1_1[data1] + | ega_lo_graph_1_2[data2] | ega_lo_graph_1_3[data3]; + dest_ptr++; + + *(dest_ptr + longs_per_scanline) + = *dest_ptr + = ega_lo_graph_0_0[data0] | ega_lo_graph_0_1[data1] + | ega_lo_graph_0_2[data2] | ega_lo_graph_0_3[data3]; + dest_ptr++; + mem_loc++; + } + while(--local_width); + save_dest_ptr += 2 * longs_per_scanline; + offset += bpl; + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = FALSE; + + /* Display the new image. */ + rect.Left = screen_x << 1; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 4) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_ega_lo_frozen_std. fs switch?"); + if (fMutexTaken) + RelMutex(sc.ConsoleBufInfo.hMutex); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint frozen screen (MODE 14: PC 640x200. SoftPC 640x400) :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_med_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG local_height, + local_width, + longs_per_scanline, + *dest_ptr, + *ref_dest_ptr, + *lut0_ptr = ega_med_and_hi_graph_luts, + *lut1_ptr = lut0_ptr + LUT_OFFSET, + *lut2_ptr = lut1_ptr + LUT_OFFSET, + *lut3_ptr = lut2_ptr + LUT_OFFSET, + *l_ptr, + hi_res, + lo_res, + mem_loc, + bpl = get_bytes_per_line(), + plane_mask = get_plane_mask(), + mem_x = screen_x >> 3, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height >> 1; + UTINY *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + SMALL_RECT rect; + BOOL fMutexTaken = FALSE; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_med_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((mem_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_ega_med_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (mem_x + width > max_width) + width = max_width - mem_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* + * Build up device-independent bitmap: one PC pixel is represented by + * two host pixels, one above the other. + */ + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * longs_per_scanline + + (screen_x >> 2); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = TRUE; + + /* Build up the bitmap. */ + local_height = height; + do + { + dest_ptr = ref_dest_ptr; + mem_loc = offset; + local_width = width; + do + { + hi_res = 0; + lo_res = 0; + + /* Get 8 bytes of output data from 1 byte of plane 0 data. */ + if (plane_mask & 1) + { + l_ptr = &lut0_ptr[*(plane1_ptr + mem_loc) << 1]; + hi_res = *l_ptr++; + lo_res = *l_ptr; + } + + /* Or in the output data from plane 1 */ + if (plane_mask & 2) + { + l_ptr = &lut1_ptr[*(plane2_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Or in the output data from plane 2 */ + if (plane_mask & 4) + { + l_ptr = &lut2_ptr[*(plane3_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Or in the output data from plane 3 */ + if (plane_mask & 8) + { + l_ptr = &lut3_ptr[*(plane4_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Now store it in the bitmap. */ + *(dest_ptr + longs_per_scanline) = *dest_ptr = hi_res; + dest_ptr++; + *(dest_ptr + longs_per_scanline) = *dest_ptr = lo_res; + *dest_ptr++; + mem_loc++; + } + while (--local_width); + ref_dest_ptr += 2 * longs_per_scanline; + offset += bpl; + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = FALSE; + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_ega_med_frozen_std. fs switch?"); + if (fMutexTaken) + RelMutex(sc.ConsoleBufInfo.hMutex); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Paint frozen screen (MODE 16: PC 640x350. SoftPC 640x350) ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_ega_hi_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG local_height, + local_width, + longs_per_scanline, + *dest_ptr, + *ref_dest_ptr, + *lut0_ptr = ega_med_and_hi_graph_luts, + *lut1_ptr = lut0_ptr + LUT_OFFSET, + *lut2_ptr = lut1_ptr + LUT_OFFSET, + *lut3_ptr = lut2_ptr + LUT_OFFSET, + *l_ptr, + hi_res, + lo_res, + mem_loc, + bpl = get_bytes_per_line(), + plane_mask = get_plane_mask(), + mem_x = screen_x >> 3, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height; + UTINY *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + SMALL_RECT rect; + BOOL fMutexTaken = FALSE; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_ega_hi_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((mem_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_ega_hi_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (mem_x + width > max_width) + width = max_width - mem_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + + /* Build up the device independent bitmap. */ + local_height = height; + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + screen_y * longs_per_scanline + + (screen_x >> 2); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = TRUE; + + do + { + dest_ptr = ref_dest_ptr; + local_width = width; + mem_loc = offset; + do + { + + /* Get 8 bytes of output data from 1 byte of plane 0 data. */ + if (plane_mask & 1) + { + l_ptr = &lut0_ptr[*(plane1_ptr + mem_loc) << 1]; + hi_res = *l_ptr++; + lo_res = *l_ptr; + } + + /* Or in the output data from plane 1 */ + if (plane_mask & 2) + { + l_ptr = &lut1_ptr[*(plane2_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Or in the output data from plane 2 */ + if (plane_mask & 4) + { + l_ptr = &lut2_ptr[*(plane3_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Or in the output data from plane 3 */ + if (plane_mask & 8) + { + l_ptr = &lut3_ptr[*(plane4_ptr + mem_loc) << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + + /* Now store it in the bitmap. */ + *dest_ptr++ = hi_res; + *dest_ptr++ = lo_res; + mem_loc++; + } + while (--local_width); + ref_dest_ptr += longs_per_scanline; + offset += bpl; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + fMutexTaken = FALSE; + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_ega_hi_frozen_std. fs switch?"); + if (fMutexTaken) + RelMutex(sc.ConsoleBufInfo.hMutex); + return; + } +} +#endif /* MONITOR */ diff --git a/private/mvdm/softpc.new/host/src/nt_emm.c b/private/mvdm/softpc.new/host/src/nt_emm.c new file mode 100644 index 000000000..79a8204ab --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_emm.c @@ -0,0 +1,817 @@ +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + +MODULE NAME : 'Lower layer' of Expanded Memory Manager + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST + NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS INC. + +DESIGNER : J.P.Box +DATE : April '88 + +PURPOSE : NT specific code for EMS LIM rev 4.0 + implementation. + +The Following Routines are defined: + 1. host_initialise_EM() + 2. host_deinitialise_EM() + 3. host_allocate_storage() + 4. host_free_storage() + 5. host_reallocate_storage() + 6. host_map_page() + 7. host_unmap_page() + 8. host_alloc_page() + 9. host_free_page() + 10. host_copy_con_to_con() + 11. host_copy_con_to_EM() + 12. host_copy_EM_to_con() + 13. host_copy_EM_to_EM() + 14. host_exchg_con_to_con() + 15. host_exchg_con_to_EM() + 16. host_exchg_EM_to_EM() + 17. host_get_access_key() + +*/ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include "insignia.h" +#include "host_def.h" + +#ifdef LIM + +#ifndef MONITOR + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "timeval.h" +#include "xt.h" +#include "emm.h" +#include "sas.h" +#include "debug.h" +#include "umb.h" +#include "host_emm.h" +#include "nt_mem.h" + + +/* Global Variables */ + +/* Forward Declarations */ + +/* ExternalDeclarations */ + +/* Local Variables */ + +UTINY *EM_pagemap_address = 0; /* address of start of pagemap */ +sys_addr EM_base_address; /* EM base intel address */ +host_addr EM_host_base_address = 0; /* EM base host address */ + +LOCAL LONG EM_size = 0; + + sys_addr emm_start; + unsigned int emm_len; +unsigned short EM_starting_page_no; + +/* +Support for backwards LIM to speed up backwards M ports + +Defines are: + EM_host_address(offset), returns host address of offset bytes + into the LIM memory area + EM_loads(from, to, length), copies length bytes from intel 24 bit + address from, to host 32 bit address to + EM_stores(to, from, length), copies length bytes from host 32 bit + address from to intel 24 bit address to + EM_moves(from, to, length), copies length bytes from intel 24 bit + address from to intel 24 bit address to + EM_memcpy(to, from, length), copies length bytes from host 32 bit + address from to host 32 bit address to + EM_pointer(ptr, length), returns a forwards or backwards type + pointer to ptr for a buffer of size length +*/ + + +#define unix_memmove(dst,src,len) memmove((dst),(src),(len)) + +#ifdef BACK_M +#define EM_host_address(offset) (EM_host_base_address + EM_size - offset) +#define EM_loads(from, to, length) memcpy(to - (length) + 1, get_byte_addr(from) - (length) + 1, length) +#define EM_stores(to, from, length) \ + sas_overwrite_memory(to, length); \ + CopyMemory(get_byte_addr(to) - (length) + 1, from - (length) + 1, length) +#define EM_moves(from,to,length) \ + sas_overwrite_memory(to, length); \ + MoveMemory(get_byte_addr(to) - (length) + 1, get_byte_addr(from) - (length) + 1, length) +#define EM_memcpy(to, from, length) \ + MoveMemory((to) - (length) + 1, (from) - (length) + 1, length) +#define EM_pointer(ptr, length) (ptr + length - 1) +#else +#define EM_host_address(offset) (EM_host_base_address + offset) +#define EM_loads(from, to, length) memcpy(to, get_byte_addr(from), length) +#define EM_stores(to, from, length) \ + sas_overwrite_memory(to, length); \ + CopyMemory(get_byte_addr(to), from, length) +#define EM_moves(from,to,length) \ + sas_overwrite_memory(to, length); \ + MoveMemory(get_byte_addr(to), get_byte_addr(from), length) +#define EM_memcpy(to, from, length) \ + MoveMemory(to, from, length) +#define EM_pointer(ptr, length) (ptr) +#endif + +#define EM_PAGE_ADDRESS(page_no) (EM_base_address + page_no * EMM_PAGE_SIZE) + + +/* +=========================================================================== + +FUNCTION : host_initialise_EM + +PURPOSE : allocates the area of memory that is used for + expanded memory and sets up an area of memory to be used + for the logical pagemap allocation table. + + +RETURNED STATUS : SUCCESS - memory allocated successfully + FAILURE - unable to allocate required space + +DESCRIPTION : + + +========================================================================= +*/ +int host_initialise_EM(short size) + +/* IN short size size of area required in megabytes */ + + +{ + long *pagemap_ptr; /* temp ptr. to logical pagemap */ + short i; /* loop counter */ + NTSTATUS status; + + status = VdmAllocateVirtualMemory(&EM_base_address, size * 0x100000, FALSE); + if (!NT_SUCCESS(status)) { +#ifdef EMM_DEBUG + printf("Couldn't allocate virtual memory for EMM, error code = %lx\n", + status); +#endif + return FAILURE; + } +#ifdef EMM_DEBUG + printf("EMM base address = %lx\n", ((sys_addr)EM_base_address); +#endif + + /* pagemap requires 1 bit per 16K page - i.e. 8 bytes per meg */ + + if((EM_pagemap_address = (byte *)host_malloc(size * 8)) == (byte *)0) + return(FAILURE); + + /* initialise pagemap to 0's */ + + pagemap_ptr = (long *)EM_pagemap_address; + for(i = 0; i < size * 2; i++) + *pagemap_ptr++ = 0; + + EM_size = ((long) size) * 0x100000; + EM_starting_page_no = (unsigned short)(EM_base_address / INTEL_PAGE_SIZE); + EM_host_base_address = get_byte_addr((sys_addr)EM_base_address); + + return(SUCCESS); + + +} + + +/* +=========================================================================== + +FUNCTION : host_deinitialise_EM + +PURPOSE : frees the area of memory that was used for + expanded memory and memory used + for the logical pagemap allocation table. + + +RETURNED STATUS : SUCCESS - memory freed successfully + FAILURE - error ocurred in freeing memory + +DESCRIPTION : + + +========================================================================= +*/ +int host_deinitialise_EM() + +{ + + if(EM_base_address != 0) + VdmFreeVirtualMemory(EM_base_address); + + if(EM_pagemap_address != (UTINY *)0) + free(EM_pagemap_address); + + EM_size = 0; + + return(SUCCESS); + + +} + + +/* +=========================================================================== + +FUNCTION : host_allocate_storage + +PURPOSE : allocates an area of memory of requested size, to be + used as a general data storage area. The area is + to zeros. + +RETURNED STATUS : storage_ID - (in this case a pointer) + NULL - failure to allocate enough space. + + +DESCRIPTION : calloc is similar to malloc but returns memory + initialised to zeros. + The storage ID returned is a value used to later reference + the storage area allocated. The macro USEBLOCK in + "host_emm.h" is used by the manager routines to convert + this ID into a char pointer + +========================================================================= +*/ +long host_allocate_storage(int no_bytes) + +/* IN int no_bytes no. of bytes required */ + +{ + return ((long)calloc(1, no_bytes)); +} + + +/* +=========================================================================== + +FUNCTION : host_free_storage + +PURPOSE : frees the area of memory that was used for + data storage + + +RETURNED STATUS : SUCCESS - memory freed successfully + FAILURE - error ocurred in freeing memory + +DESCRIPTION : In this implementation storage_ID is simply a pointer + + +========================================================================= +*/ +int host_free_storage(long storage_ID) + +/* IN long storage_ID ptr to area of memory */ + +{ + + if(storage_ID != (long) 0) + free((char *)storage_ID); + + return(SUCCESS); + +} + + +/* +=========================================================================== + +FUNCTION : host_reallocate_storage + +PURPOSE : increases the size of memory allocated, maintaining the + contents of the original memory block + + +RETURNED STATUS : storage_ID - memory reallocated successfully + NULL - error ocurred in reallocating memory + +DESCRIPTION : In this implementation storage_ID is simply a pointer + Note the value of storage_ID returned may or may not be the + same as the value given + +========================================================================= +*/ +long host_reallocate_storage(long storage_ID, int size, int new_size) + +/* IN +long storage_ID ptr to area of memory +int size original size - not used in this version + new_size new size required +*/ +{ + return((long)realloc((char *)storage_ID, new_size)); +} + + +/* +=========================================================================== + +FUNCTION : host_map_page + +PURPOSE : produces mapping from an Expanded Memory page to a + page in Intel physical address space + + +RETURNED STATUS : SUCCESS - mapping completed succesfully + FAILURE - error ocurred in mapping + +DESCRIPTION : Mapping achieved by simply copying data from the + expanded memory to Intel memory + +========================================================================= +*/ +int host_map_page(short EM_page_no, unsigned short segment) + +/* IN +short EM_page_no; Expanded Memory page to be mapped in +unsigned short segment; segment in physical address space to + map into +*/ + +{ + ULONG DosIntelPageNo, VdmIntelPageNo; + NTSTATUS Status; + + DosIntelPageNo = SEGMENT_TO_INTEL_PAGE(segment); + VdmIntelPageNo = EMM_PAGE_TO_INTEL_PAGE(EM_page_no) + + EM_starting_page_no; + + + note_trace2(LIM_VERBOSE,"map page %d to segment 0x%4x", EM_page_no, segment); + Status = VdmMapDosMemory(DosIntelPageNo, + VdmIntelPageNo, + EMM_PAGE_SIZE / INTEL_PAGE_SIZE + ); +#ifdef EMM_DEBUG + printf("host_map_page, segment=%x, EMpage=%x, Dospage=%x, VdmPage=%x\n", + segment, EM_page_no, DosIntelPageNo, VdmIntelPageNo); +#endif + if (NT_SUCCESS(Status)) { + return(SUCCESS); + } + else + return(FAILURE); + + +} + +/* +=========================================================================== + +FUNCTION : host_unmap_page + +PURPOSE :unmaps pages from Intel physical address space to an + Expanded Memory page + +RETURNED STATUS : SUCCESS - unmapping completed succesfully + FAILURE - error ocurred in mapping + +DESCRIPTION : Unmapping achieved by simply copying data from Intel + memory to expanded memory + +========================================================================= +*/ +int host_unmap_page(unsigned short segment, short EM_page_no) + +/* IN +unsigned short segment segment in physical address space to + unmap +short EM_page_no Expanded Memory page currently + mapped in +*/ + +{ + ULONG DosIntelPageNo, VdmIntelPageNo; + NTSTATUS Status; + + DosIntelPageNo = SEGMENT_TO_INTEL_PAGE(segment); + VdmIntelPageNo = EMM_PAGE_TO_INTEL_PAGE(EM_page_no) + + EM_starting_page_no; + +#ifdef EMM_DEBUG + printf("host_unmap_page, segment=%x, EMpage=%x, Dospage=%x, VdmPage=%x\n", + segment, EM_page_no, DosIntelPageNo, VdmIntelPageNo); +#endif + Status = VdmUnmapDosMemory(DosIntelPageNo, + EMM_PAGE_SIZE / INTEL_PAGE_SIZE + ); + + note_trace2(LIM_VERBOSE,"unmap page %d from segment 0x%.4x\n",EM_page_no,segment); + if (NT_SUCCESS(Status)) + return (SUCCESS); + else + return(FAILURE); + +} + + +/* +=========================================================================== + +FUNCTION : host_alloc_page + +PURPOSE : searches the pagemap looking for a free page, allocates + that page and returns the EM page no. + +RETURNED STATUS : + SUCCESS - Always see note below + +DESCRIPTION : Steps through the Expanded memory Pagemap looking for + a clear bit, which indicates a free page. When found, + sets that bit and returns the page number. + For access purposes the pagemap is divided into long + word(32bit) sections + +NOTE : The middle layer calling routine (alloc_page()) checks + that all pages have not been allocated and therefore in + this implementation the returned status will always be + SUCCESS. + However alloc_page still checks for a return status of + SUCCESS, as some implementations may wish to allocate pages + dynamically and that may fail. +========================================================================= +*/ +short host_alloc_page() + +{ + short EM_page_no; /* page number returned */ + long *ptr; /* ptr to 32 bit sections in */ + /* pagemap */ + short i; /* index into 32 bit section */ + + NTSTATUS status; + + ptr = (long *)EM_pagemap_address; + i =0; + EM_page_no = 0; + + while(*ptr & (MSB >> i++)) + { + EM_page_no++; + + if(i == 32) + /* + * start on next section + */ + { + ptr++; + i = 0; + } + } + /* + * Set bit to show that page is allocated + */ + *ptr = *ptr | (MSB >> --i); + + /* commit memory to the page */ + status = VdmCommitVirtualMemory(EM_PAGE_ADDRESS(EM_page_no), + EMM_PAGE_SIZE + ); + + if (!NT_SUCCESS(status)) + return FAILURE; + return(EM_page_no); +} + + +/* +=========================================================================== + +FUNCTION : host_free_page + +PURPOSE : marks the page indicated as being free for further + allocation + +RETURNED STATUS : + SUCCESS - Always - see note below + +DESCRIPTION : clears the relevent bit in the pagemap. + + For access purposes the pagemap is divided into long + word(32bit) sections. + +NOTE : The middle layer calling routine (free_page()) always + checks for invalid page numbers so in this implementation + the routine will always return SUCCESS. + However free_page() still checks for a return of SUCCESS + as other implementations may wish to use it. +========================================================================= +*/ +int host_free_page(short EM_page_no) + +/* IN short EM_page_no page number to be cleared */ + + +{ + long *ptr; /* ptr to 32 bit sections in */ + /* pagemap */ + short i; /* index into 32 bit section */ + + + NTSTATUS status; + + status = VdmDeCommitVirtualMemory(EM_PAGE_ADDRESS(EM_page_no), + EMM_PAGE_SIZE + ); + + if (!NT_SUCCESS(status)) + return FAILURE; + /* + * Set pointer to correct 32 bit section and index to correct bit + */ + + ptr = (long *)EM_pagemap_address; + ptr += (EM_page_no / 32); + i = EM_page_no % 32; + + /* + * clear bit + */ + *ptr = *ptr & ~(MSB >> i); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_copy routines + host_copy_con_to_con() + host_copy_con_to_EM() + host_copy_EM_to_con() + host_copy_EM_to_EM() + +PURPOSE : copies between conventional and expanded memory + + +RETURNED STATUS : + SUCCESS - Always - see note below + +DESCRIPTION : + The middle layer calling routine always checks for a + return of SUCCESS as other implementations may + return FAILURE. +========================================================================= +*/ +int host_copy_con_to_con(int length, unsigned short src_seg, + unsigned short src_off, unsigned short dst_seg, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_seg source segment address + src_off source offset address + dst_seg destination segment address + dst_off destination offset address +*/ +{ + sys_addr from, to; /* pointers used for copying */ + + from = effective_addr(src_seg, src_off); + to = effective_addr(dst_seg, dst_off); + + EM_moves(from, to, length); + + return(SUCCESS); +} + +int host_copy_con_to_EM(int length, unsigned short src_seg, + unsigned short src_off, unsigned short dst_page, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_seg source segment address + src_off source offset address + dst_page destination page number + dst_off destination offset within page +*/ +{ + unsigned char *to; /* pointers used for copying */ + sys_addr from; + + from = effective_addr(src_seg, src_off); + to = EM_host_address(dst_page * EMM_PAGE_SIZE + dst_off); + + EM_loads(from, to, length); + + return(SUCCESS); +} + +int host_copy_EM_to_con(int length, unsigned short src_page, + unsigned short src_off, unsigned short dst_seg, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_page source page number + src_off source offset within page + dst_seg destination segment address + dst_off destination offset address +*/ +{ + unsigned char *from; /* pointers used for copying */ + sys_addr to; + + from = EM_host_address(src_page * EMM_PAGE_SIZE + src_off); + to = effective_addr(dst_seg, dst_off); + + EM_stores(to, from, length); + + return(SUCCESS); +} + +int host_copy_EM_to_EM(int length, unsigned short src_page, + unsigned short src_off, unsigned short dst_page, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_page source page number + src_off source offset within page + dst_page destination page number + dst_off destination offset within page +*/ +{ + unsigned char *from, *to; /* pointers used for copying */ + + from = EM_host_address(src_page * EMM_PAGE_SIZE + src_off); + to = EM_host_address(dst_page * EMM_PAGE_SIZE + dst_off); + + EM_memcpy(to, from, length); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_exchange routines + host_exchg_con_to_con() + host_exchg_con_to_EM() + host_exchg_EM_to_EM() + +PURPOSE : exchanges data between conventional and expanded memory + + +RETURNED STATUS : + SUCCESS - Everything ok + FAILURE - Memory allocation failure + +DESCRIPTION : + +========================================================================= +*/ +int host_exchg_con_to_con(int length, unsigned short src_seg, + unsigned short src_off, unsigned short dst_seg, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_seg source segment address + src_off source offset address + dst_seg destination segment address + dst_off destination offset address +*/ +{ + unsigned char *temp, *pointer;/* pointers used for copying */ + sys_addr to, from; + + if ((temp = (unsigned char *)host_malloc(length)) == (unsigned char *)0) + return(FAILURE); + + pointer = EM_pointer(temp, length); + + from = effective_addr(src_seg, src_off); + to = effective_addr(dst_seg, dst_off); + + EM_loads(from, pointer, length); /* source -> temp */ + EM_moves(to, from, length); /* dst -> source */ + EM_stores(to, pointer, length); /* temp -> dst */ + + free(temp); + + return(SUCCESS); +} + +int host_exchg_con_to_EM(int length, unsigned short src_seg, + unsigned short src_off, unsigned short dst_page, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_seg source segment address + src_off source offset address + dst_page destination page number + dst_off destination offset within page +*/ +{ + unsigned char *to, *temp, *pointer;/* pointers used for copying */ + sys_addr from; + + if ((temp = (unsigned char *)host_malloc(length)) == (unsigned char *)0) + return(FAILURE); + + pointer = EM_pointer(temp, length); + + from = effective_addr(src_seg, src_off); + to = EM_host_address(dst_page * EMM_PAGE_SIZE + dst_off); + + EM_loads(from, pointer, length); + EM_stores(from, to, length); + EM_memcpy(to, pointer, length); + + free(temp); + + return(SUCCESS); +} + +int host_exchg_EM_to_EM(int length, unsigned short src_page, + unsigned short src_off, unsigned short dst_page, + unsigned short dst_off) + +/* IN +int length number of bytes to copy + +unsigned short src_page source page number + src_off source offset within page + dst_page destination page number + dst_off destination offset within page +*/ +{ + unsigned char *from, *to, *temp, *pointer; + /* pointers used for copying */ + + if ((temp = (unsigned char *)host_malloc(length)) == (unsigned char *)0) + return(FAILURE); + + pointer = EM_pointer(temp, length); + + from = EM_host_address(src_page * EMM_PAGE_SIZE + src_off); + to = EM_host_address(dst_page * EMM_PAGE_SIZE + dst_off); + + EM_memcpy(pointer, from, length); + EM_memcpy(from, to, length); + EM_memcpy(to, pointer, length); + + free(temp); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_get_access_key + +PURPOSE : produces a random access key for use with LIM function 30 + 'Enable/Disable OS/E Function Set Functions' + +RETURNED STATUS : none + +DESCRIPTION : Two 16 bit random values are required for the 'access key' + We use the microsecond field from the get time of day routine + to provide this. + +========================================================================= +*/ +void host_get_access_key(unsigned short access_key[2]) + +/* OUT unsigned short access_key[2] source segment address */ + +{ + struct host_timeval time; /* structure for holding time */ + + host_GetSysTime(&time); + + access_key[0] = time.tv_usec & 0xffff; + access_key[1] = (time.tv_usec >> 3) & 0xffff; + + return; +} + +#endif /* MONITOR */ + +#endif /* LIM */ diff --git a/private/mvdm/softpc.new/host/src/nt_eoi.c b/private/mvdm/softpc.new/host/src/nt_eoi.c new file mode 100644 index 000000000..05653c2d5 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_eoi.c @@ -0,0 +1,545 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Host EOI hook controller + * + * Description : This module handles host specific ica code + * - EOI hook + * - ICA lock + * + * Author : D.A.Bartlett + * + * Notes : 30-Oct-1993 Jonle , Rewrote it + */ + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntexapi.h> +#include <windows.h> +#include <stdio.h> +#include <vdm.h> +#include "insignia.h" +#include "host_def.h" +#include "xt.h" +#include CpuH +#include "sas.h" +#include "quick_ev.h" +#include "ica.h" +#include "host_rrr.h" +#include "error.h" +#include "nt_uis.h" +#include "nt_reset.h" +#include "nt_eoi.h" + +// from monitor.lib +HANDLE ThreadLookUp(PVOID); +extern PVOID CurrentMonitorTeb; + +// from nt_timer.c +extern ULONG GetPerfCounter(VOID); + + +RTL_CRITICAL_SECTION IcaLock; // ICA critical section lock +ULONG UndelayIrqLine=0; +ULONG DelayIrqLine=0xffffffff; // all ints are blocked until, spckbd loaded + +#ifdef MONITOR +ULONG iretHookActive=0; +ULONG iretHookMask =0; +ULONG AddrIretBopTable=0; // seg:offset +#endif + +HANDLE hWowIdleEvent = INVALID_HANDLE_VALUE; + +/* + * EOI defines, types, global data + * + */ +static EOIHOOKPROC EoiHooks[16]={NULL}; // must be init to NULL + + +#ifndef MONITOR +void DelayIrqQuickEvent(long param); +q_ev_handle DelayHandle[16]; +#define pNtVDMState ((PULONG)(Start_of_M_area + FIXED_NTVDMSTATE_LINEAR)) + +LARGE_INTEGER BlockTime = {0,0}; +extern LARGE_INTEGER CurrHeartBeat; +void host_TimeStamp(PLARGE_INTEGER pliTime); +#endif + + +/* + * Called by wow32 to fetch the hWowIdleEvent, which wowexec waits on + * in the wow nonpreemptive scheduler. + */ +HANDLE RegisterWOWIdle(VOID) +{ + return hWowIdleEvent; +} + +/* + * Called by WOW32 to inform the WOW idle code that the current WOW + * task may be scheduled\descheduled. + */ + +void +BlockWOWIdle( + BOOL Blocking + ) +{ + host_ica_lock(); + + if (Blocking) { + *pNtVDMState |= VDM_WOWBLOCKED; + +#ifndef MONITOR + BlockTime = CurrHeartBeat; +#endif + + } + else { + *pNtVDMState &= ~VDM_WOWBLOCKED; + + + +#ifndef MONITOR + if (BlockTime.QuadPart && + (CurrHeartBeat.QuadPart >= BlockTime.QuadPart + SYSTEM_TICK_INTV/2)) + { + BlockTime.QuadPart = 0; + host_ica_unlock(); + + ActivityCheckAfterTimeSlice(); + return; + } +#endif + } + + host_ica_unlock(); +} + + + +/* + * (WOWIdle)...check if an app requires hw interrupts servicing but all WOW + * threads are blocked. If so then the call will cause wowexec to awaken + * to handle them. Called from ica interrupt routines. NB. Default action + * of routine is to check state and return as fast as possible. + */ +void +WOWIdle( + BOOL Force + ) +{ + if (VDMForWOW && (Force || (*pNtVDMState & VDM_WOWBLOCKED))) { + SetEvent(hWowIdleEvent); + } + +} + + + + +/* RegisterEoiHook + * + * Registers an call back function to be invoked upon eoi of + * a hardware interrupt. + * + * entry: IrqLine - IrqNumber to register + * EoiHookProc - function pointer to be called upon eoi + * + * returns FALSE if the the IrqLine already has an eoi hook registered + */ +BOOL RegisterEOIHook(int IrqLine, EOIHOOKPROC EoiHookProc) +{ + + if (!EoiHooks[IrqLine]) { + EoiHooks[IrqLine] = EoiHookProc; + return(TRUE); + } + + return(FALSE); +} + + + +/* RemoveEOIHook + * + * entry: IrqLine - IrqNumber to remove + * EoiHookProc - function pointer previously registered + */ +BOOL RemoveEOIHook(int IrqLine, EOIHOOKPROC EoiHookProc) +{ + if (EoiHooks[IrqLine] == EoiHookProc) { + EoiHooks[IrqLine] = NULL; + return(TRUE); + } + return(FALSE); +} + + + +/* host_EOI_hook + * + * base callback function to invoke device specific Eoi Hook routines + * + * Entry: IrqLine - Line number + * CallCount - The ica Call count for this Irq + * If the Call count is -1 then a pending + * interrupt is being canceled. + * + */ +VOID host_EOI_hook(int IrqLine, int CallCount) +{ + if ((ULONG)IrqLine >= sizeof(EoiHooks)/sizeof(EOIHOOKPROC)) { +#if DBG + DbgPrint("ntvdm.Eoi_hook: Invalid IrqLine=%lx\n", (ULONG)IrqLine); +#endif + return; + } + + if (EoiHooks[IrqLine]) { + (*EoiHooks[IrqLine])(IrqLine, CallCount); + } +} + + +/* host_DelayHwInterrupt + * + * base callback function to queue a HW interrupt at a later time + * + * entry: IrqLineNum - Irq Line Number + * CallCount - Number of interrupts, May be Zero + * Delay - Delay time in usecs + * if Delay is 0xFFFFFFFF then per IrqLine data + * structures are freed, use for cleanup when + * the IrqLine is no longer needed for DelayedInterrupts + * + * Notes: The expected granularity is around 1 msec, but varies depending + * on the platform. + * + * + */ +BOOL host_DelayHwInterrupt(int IrqLineNum, int CallCount, ULONG Delay) +{ + int adapter; + ULONG IrqLine; + +#ifdef MONITOR + NTSTATUS status; + VDMDELAYINTSDATA DelayIntsData; +#else + ULONG TicCount; +#endif + + host_ica_lock(); + + // + // Anything to do (only one delayed Irql at a time) + // + + IrqLine = 1 << IrqLineNum; + if (!(DelayIrqLine & IrqLine) || Delay == 0xffffffff) { + + // + // force a minimum delay of 1 ms + // + if (Delay < 1000) { + Delay = 1000; + } + +#ifdef MONITOR + + // + // Set Kernel timer for this IrqLine + // + DelayIntsData.Delay = Delay; + DelayIntsData.DelayIrqLine = IrqLineNum; + DelayIntsData.hThread = ThreadLookUp(CurrentMonitorTeb); + if (DelayIntsData.hThread) { + status = NtVdmControl(VdmDelayInterrupt, &DelayIntsData); + if (!NT_SUCCESS(status)) { +#if DBG + DbgPrint("NtVdmControl.VdmDelayInterrupt status=%lx\n",status); +#endif + host_ica_unlock(); + return FALSE; + } + + } + +#else + + // + // Cancel delay hw interrupt, delete quick event if any + // + if (Delay == 0xFFFFFFFF) { + if (DelayHandle[IrqLineNum]) { + delete_q_event(DelayHandle[IrqLineNum]); + DelayIrqLine &= ~IrqLine; + DelayHandle[IrqLineNum] = 0; + } + host_ica_unlock(); + return TRUE; + } + + + // + // Mark The IrqLine as delayed until timer fires and queue a quick + // event, (a bit early for overhead in dispatching quick events). + // + DelayIrqLine |= IrqLine; + DelayHandle[IrqLineNum] = add_q_event_i(DelayIrqQuickEvent, + Delay - 200, + IrqLineNum + ); + + // + // Keep Wow Tasks active + // + WOWIdle(TRUE); + + + +#endif + } + + + // + // If we have more interrupts to generate, register them + // + if (CallCount) { + adapter = IrqLineNum >> 3; + ica_hw_interrupt(adapter, + (UCHAR)(IrqLineNum - (adapter << 3)), + CallCount + ); + } + + + host_ica_unlock(); + return TRUE; +} + + + +#ifndef MONITOR +/* + * QuickEvent call back function + * + */ +void DelayIrqQuickEvent(long param) +{ + ULONG IrqLineNum = param; + + host_ica_lock(); + + DelayHandle[IrqLineNum] = 0; + ica_RestartInterrupts(1 << IrqLineNum); + + host_ica_unlock(); + +} +#endif + + + +// ICA critical section locking code +// This is needed to control access to the ICA from different threads. + +void host_ica_lock(void) +{ + RtlEnterCriticalSection(&IcaLock); +} + +void host_ica_unlock(void) +{ + RtlLeaveCriticalSection(&IcaLock); +} + +void InitializeIcaLock(void) +{ + RtlInitializeCriticalSection(&IcaLock); + + + if (VDMForWOW) { + if(!(hWowIdleEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + TerminateVDM(); + } + } +} + + + +#ifdef MONITOR +// +// Force creation of the LazyCreate LockSemaphore +// for the ica lock. +// It is assumed that: +// the cpu thread Owns the critsect +// the HeartBeat Thread will wait on the critsect creating contention +// +// This is done by polling for a lock count greater than zero +// and verifying that the lock semaphore has been created. +// If these conditions are not met we will end up polling infinitely. +// Sounds dangerous but it is okay, since we will either get a +// CreateSemaphore or a timeout(deadlock) error from the rtl critical +// section code, which will result in an exception. +// +VOID WaitIcaLockFullyInitialized(VOID) +{ + DWORD Delay = 0; + + do { + Sleep(Delay++); + } while (IcaLock.LockCount < 1 || !IcaLock.LockSemaphore); +} +#endif + + + +// The following routines are used to support IRET hooks. If an interrupt +// uses an IRET hook then the ICA will not generate a interrupt of that +// type until the IRET hook has been called. + + +// Exported for vdmredir + +void SoftPcEoi(int Adapter, int* Line) { + ica_eoi(Adapter, Line, 0); +} + + + + +// +// Restart delayed interrupts +// IcaLock should be held upon entry +// + +BOOL ica_restart_interrupts(int adapter) +{ + int i; + + if((i = ica_scan_irr(adapter)) & 0x80) { + ica_interrupt_cpu(adapter, i &= 0x07); + return TRUE; + } + + return FALSE; +} +//New ICA interrupt state reset function + +void ica_reset_interrupt_state(void) +{ + int line_no; + + host_ica_lock(); + + for(line_no = 0; line_no < 8; line_no++) { + VirtualIca[ICA_MASTER].ica_count[line_no] = + VirtualIca[ICA_SLAVE].ica_count[line_no] = 0; + ica_clear_int(ICA_MASTER,line_no); + ica_clear_int(ICA_SLAVE,line_no); + } + + + //Clear interrupt counters + VirtualIca[ICA_MASTER].ica_cpu_int = + VirtualIca[ICA_SLAVE].ica_cpu_int = FALSE; + +#ifdef MONITOR + iretHookActive = 0; +#endif + DelayIrqLine = 0; + + //Tell CPU to remove any pending interrupts + host_clear_hw_int(); + + host_ica_unlock(); +} + + +/* + * Handle callout from DPMI to say that an app has asked DPMI to switch it + * to protected mode. We use this as an indicator that a protected mode app + * will work with the Iret Hook system. If an app does it's own thing with + * selectors et al, the BOP table will be hidden, swallowed and generally + * lost. Attempts then to transfer control to it will fault. + * Known examples of such unfriendliness are the DOS Lotus 123 r3 series. + */ +VOID EnableEmulatorIretHooks(void) +{ + ; // obsolete +} + +/* + * The app is closing - turn off the Iret Hooks in case the next app is + * iret hook unfriendly. If it's a friendly app, we'll be called again + * via the Enable... routine above. + */ +VOID DisableEmulatorIretHooks(void) +{ + ; // obsolete +} + +// +// Retry DelayInts (not iret hooks!) +// +// IrqLine - IrqLineBitMask, to be cleared +// +VOID ica_RestartInterrupts(ULONG IrqLine) +{ +#ifdef MONITOR + + // + // on x86 we may get multiple bits set + // so check both slave and master + // + UndelayIrqLine = 0; + + if (!ica_restart_interrupts(ICA_SLAVE)) + ica_restart_interrupts(ICA_MASTER); +#else + host_ica_lock(); + + DelayIrqLine &= ~IrqLine; + + ica_restart_interrupts(IrqLine >> 3 ? ICA_SLAVE : ICA_MASTER); + + host_ica_unlock(); +#endif +} + +#ifdef MONITOR +extern IU16 getMSW(void); + +IU32 host_iret_bop_table_addr(IU32 line) +{ + ULONG AddrBopTable, IretBopSize; + + ASSERT(line <= 15); + + if (!(iretHookMask & (1 << line))) { + return 0; + } + + if (getMSW() & 1) { + AddrBopTable = (VDM_PM_IRETBOPSEG << 16) | VDM_PM_IRETBOPOFF; + IretBopSize = VDM_PM_IRETBOPSIZE; + } + else { + AddrBopTable = AddrIretBopTable; + IretBopSize = VDM_RM_IRETBOPSIZE; + } + return AddrBopTable + IretBopSize * line; + +} +#endif /* MONITOR */ diff --git a/private/mvdm/softpc.new/host/src/nt_error.c b/private/mvdm/softpc.new/host/src/nt_error.c new file mode 100644 index 000000000..9f8757655 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_error.c @@ -0,0 +1,1190 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntstatus.h> +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <conapi.h> +#include "insignia.h" +#include "host_def.h" +/* + * SoftPC Revision 2.0 + * + * Title : General Error Handler + * + * Description : General purpose error handler. It handles both + * general SoftPC errors (error numbers 0 - 999) and + * host specific errors (error numbers >= 1000) + * + * Author(s) : Dave Bartlett (based on module by John Shanly) + * + * Parameters : int used to index an array of error messages + * held in message.c, and a bit mask indicating + * the user's possible options: + * Quit, Reset, Continue, Setup + * + */ + + +#include <sys/types.h> +#include <string.h> +#include <malloc.h> +#include <stdio.h> + +#include "xt.h" +#include CpuH +#include "sas.h" +#include "bios.h" +#include "ios.h" +#include "gvi.h" +#include "error.h" +#include "config.h" +#include "dterm.h" +#include "host_rrr.h" +#include "host_nls.h" + +#include "nt_graph.h" +#include "nt_uis.h" +#include "nt_reset.h" +#include "ckmalloc.h" + +#include "trace.h" +#include "nt_event.h" + + + +extern VOID (*pW32HungAppNotifyThread)(UINT); +int error_window_options = 0; + +VOID SuspendTimerThread(VOID); +VOID ResumeTimerThread(VOID); + + +/*::::::::::::::::::::::::::::::::: Internally used variables and functions */ + +typedef struct _ErrorDialogBoxInfo{ + DWORD dwOptions; + DWORD dwReply; + HWND hWndCon; + char *message; + char *pEdit; + char Title[MAX_PATH]; + }ERRORDIALOGINFO, *PERRORDIALOGINFO; + +char achPERIOD[]=". "; + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: STDOUT macro */ + +#define ERRORMSG OutputDebugString +#define HIDEDLGITM(d,b) ShowWindow(GetDlgItem(d,b),SW_HIDE); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int ErrorDialogBox(char *message, char *Edit, DWORD dwOptions); +DWORD ErrorDialogBoxThread(VOID *pv); +int WowErrorDialogEvents(ERRORDIALOGINFO *pedgi); +LONG APIENTRY ErrorDialogEvents(HWND hDlg,WORD wMsg,LONG wParam,LONG lParam); +void SwpButtons(HWND hDlg, DWORD dwOptions); +void SwpDosDialogs(HWND hDlg, HWND hWndCon,HWND SwpInsert, UINT SwpFlags); +DWORD OemMessageToAnsiMessage(CHAR *, CHAR *); +DWORD AnsiMessageToOemMessage(CHAR *pBuff, CHAR *pMsg); +ULONG WOWpSysErrorBox(LPSTR,LPSTR,USHORT,USHORT,USHORT); + + +#ifndef MONITOR + + /* + * Do things the old fashioned way for some of the cpu building tools + * which cannot be changed to match our host + */ + + +#ifdef host_error_ext +#undef host_error_ext +#endif +SHORT host_error_ext(int error_num, int options, ErrDataPtr data) +{ + return host_error(error_num, options, NULL); +} + +#ifdef host_error +#undef host_error +#endif +SHORT host_error(int error_num, int options, char *extra_char); + +#ifdef host_error_conf +#undef host_error_conf +#endif +SHORT host_error_conf(int config_panel, int error_num, int options, + char *extra_char) +{ + return host_error(error_num, options, extra_char); +} + +ERRORFUNCS nt_error_funcs = { host_error_conf,host_error,host_error_ext}; +ERRORFUNCS *working_error_funcs = &nt_error_funcs; +#endif + + + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Display error, terminate ::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int DisplayErrorTerm(int ErrorNo, /* Softpc Error number */ + DWORD OSErrno, /* OS Error number */ + char *Filename, /* File name of file containing err */ + int Lineno) /* LIne number of error */ +{ + char Msg[EHS_MSG_LEN]; + DWORD errno, len; + + UNUSED(ErrorNo); //Always internal error + +#ifndef PROD + sprintf(Msg,"NTVDM:ErrNo %#x, %s:%d\n", OSErrno, Filename, Lineno); + OutputDebugString(Msg); +#endif + + // assume NT error if either of top two bits set (err or warning). + // this means we'll confuse some of the lesser NT errors but we get a + // second chance if the mapping fails. + if (OSErrno & 0xc0000000) + errno = RtlNtStatusToDosError(OSErrno); + else + errno = OSErrno; + + // Now get message from system + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errno, + 0, + Msg, + EHS_MSG_LEN, + NULL + ); + if (!len) { + sprintf(Msg, "%s %lxh", szSysErrMsg, OSErrno); + } + + return(host_error(EHS_SYSTEM_ERROR, ERR_QUIT, Msg)); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Display host error ::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +SHORT host_error(int error_num, int options, char *extra_char) +{ + char message[EHS_MSG_LEN]; + + host_nls_get_msg(error_num, message, EHS_MSG_LEN); + + if (extra_char && *extra_char) { + strcat(message,"\n"); + strcat(message,extra_char); + } + + +#ifndef PROD + OutputDebugString(message); + if (extra_char) { + OutputDebugString("\n"); + } +#endif + + ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE); + + return ERR_CONT; +} + + +DWORD TlsDirectError; +// +// Called directly from C or via bop. Type checked against global 'DirectError' +// to see if called already in this app. 'DirectError' cleared on VDM resume. +// +// This function is expected to be called by 16 bit threads +// which is doing the unsupported service. For DosApps this is +// the CPU thread, For WOW this is one of the individual 16 bit tasks. +// +// +VOID host_direct_access_error(ULONG type) +{ + CHAR message[EHS_MSG_LEN]; + CHAR acctype[EHS_MSG_LEN]; + CHAR dames[EHS_MSG_LEN]; + DWORD dwDirectError; + + + /* + * Get the direct error record for the current thread + * if TlsGetValue returns NULL + * - could be invalid index (TlsAlloc failed) + * - actual value is 0, (no bits set) + * In both cases we will go ahead with the popup + */ + dwDirectError = (DWORD)TlsGetValue(TlsDirectError); + + // don't annoy user with repeated popups + if ((dwDirectError & (1<<type)) != 0) + return; + + TlsSetValue(TlsDirectError, (LPVOID)(dwDirectError | (1 << type))); + + if (LoadString(GetModuleHandle(NULL), D_A_MESS, + dames, sizeof(dames)/sizeof(CHAR)) && + LoadString(GetModuleHandle(NULL), D_A_MESS + type + 1, + acctype, sizeof(acctype)/sizeof(CHAR)) ) + { + sprintf(message, dames, acctype); + } + else { + strcpy(message, szDoomMsg); + } + + + ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE); +} + + +/* + * RcErrorDialogBox + * + * Displays standard dialog Box for errors and warnings + * Looks up the error message from ntvdm's reource string table + * + * entry: UINT wId - string table resource index + * CHAR *msg1 - Optional OEM strings which are displayed + * CHAR *msg2 before the main error message. Each string + * is limited to MAX_PATH inclusive of NULL, + * (auto-truncate). + * + * exit: + * + */ +void RcErrorDialogBox(UINT wId, CHAR *msg1, CHAR *msg2) +{ + DWORD dw, dwTotal; + CHAR ErrMsg[MAX_PATH*4]; + + dwTotal = 0; + dw = OemMessageToAnsiMessage(ErrMsg, msg1); + if (dw) { + dwTotal += dw; + strcpy(&ErrMsg[dwTotal], achPERIOD); + dwTotal += sizeof(achPERIOD) - 1; + } + + dw = OemMessageToAnsiMessage(&ErrMsg[dwTotal], msg2); + if (dw) { + dwTotal += dw; + strcpy(&ErrMsg[dwTotal], achPERIOD); + dwTotal += sizeof(achPERIOD) - 1; + } + + if (!LoadString(GetModuleHandle(NULL), wId, &ErrMsg[dwTotal], MAX_PATH)) + { + strcpy(ErrMsg, szDoomMsg); + } + + ErrorDialogBox(ErrMsg, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE); +} + + + +/* + * RcMessageBox + * + * Displays standard dialog Box for errors and warnings + * Looks up the error message from ntvdm's reource string table + * + * Optionally shows an edit dialog control. The edit control + * is placed just below the first line of the message text, + * leaving only enuf space to display a one line message. + * + * entry: UINT wId - string table resource index + * CHAR *msg1 - Optional OEM strings which are displayed + * CHAR *msg2 before the main error message. Each string + * is limited to MAX_PATH inclusive of NULL, + * (auto-truncate). + * + * If RMB_EDIT is specified msg2 is NOT used for messages + * to be displayed, rather is used for the default string for the + * edit control. The hiword of dwOPtions is used as max size of + * edit buffer, and must be less than MAX_PATH + * + * DWORD dwOptions - accepts + * RMB_ABORT + * RMB_RETRY + * RMB_IGNORE msg box equivalent + * RMB_ICON_INFO - IDI_ASTERICK + * RMB_ICON_BANG - IDI_EXCLAMATION + * RMB_ICON_STOP - IDI_HAND + * RMB_ICON_WHAT - IDI_QUESTION + * RMB_EDIT - edit dialog control + * + * exit: returns RMB_ABORT RMB_RETRY RMB_IGNORE RMB_EDIT + * If RMB_EDIT is specified msg2 is used to return + * the contents of the edit control + * + */ +int RcMessageBox(UINT wId, CHAR *msg1, CHAR *msg2, DWORD dwOptions) + +{ + DWORD dw, dwTotal; + char *pEdit; + CHAR ErrMsg[MAX_PATH*4]; + CHAR Edit[MAX_PATH]; + int i; + + dwTotal = 0; + dw = OemMessageToAnsiMessage(ErrMsg, msg1); + if (dw) { + dwTotal += dw; + strcpy(&ErrMsg[dwTotal], achPERIOD); + dwTotal += sizeof(achPERIOD) - 1; + } + + if (dwOptions & RMB_EDIT) { + dw = OemMessageToAnsiMessage(Edit, msg2); + pEdit = Edit; + } + else { + dw = OemMessageToAnsiMessage(&ErrMsg[dwTotal], msg2); + if (dw) { + dwTotal += dw; + strcpy(&ErrMsg[dwTotal], achPERIOD); + dwTotal += sizeof(achPERIOD) - 1; + } + pEdit = NULL; + } + + if (!LoadString(GetModuleHandle(NULL), wId, &ErrMsg[dwTotal], MAX_PATH)) + { + strcpy(ErrMsg, szDoomMsg); + } + + i = ErrorDialogBox(ErrMsg, pEdit, dwOptions); + + if (pEdit) { + AnsiMessageToOemMessage(msg2, pEdit); + } + + return i; +} + + + +/* + * AnsiMessageToOemMessage + * + * converts string messages from ansi to oem strings, for display output + * + * entry: CHAR *msg + * Each string is limited to MAX_PATH inclusive of NULL, + * (auto-truncate). + * + * CHAR *pBuff - destination buffer, must be at least MAX_PATH + * + * exit: returns string len + */ +DWORD AnsiMessageToOemMessage(CHAR *pBuff, CHAR *pMsg) +{ + PUNICODE_STRING pUnicode; + ANSI_STRING AnsiString; + OEM_STRING OemString; + + if (!pBuff) + return 0; + + if (!pMsg || !*pMsg) { + *pBuff = '\0'; + return 0; + } + + RtlInitString(&AnsiString, pMsg); + if (AnsiString.Length > MAX_PATH) { + AnsiString.Length = MAX_PATH-1; + AnsiString.MaximumLength = MAX_PATH; + } + + OemString.MaximumLength = AnsiString.MaximumLength; + OemString.Buffer = pBuff; + *(OemString.Buffer+AnsiString.Length) = '\0'; + pUnicode = &NtCurrentTeb()->StaticUnicodeString; + if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(pUnicode, + &AnsiString, + FALSE)) || + !NT_SUCCESS(RtlUnicodeStringToOemString((POEM_STRING)&OemString, + pUnicode, + FALSE)) ) + { + OemString.Length = 0; + } + + return OemString.Length; +} + + +/* + * OemMessageToAnsiMessage + * + * converts string messages from oem to ansi strings, for display output + * + * entry: CHAR *msg + * Each string is limited to MAX_PATH inclusive of NULL, + * (auto-truncate). + * + * CHAR *pBuff - destination buffer, must be at least MAX_PATH + * + * exit: returns string len + */ +DWORD OemMessageToAnsiMessage(CHAR *pBuff, CHAR *pMsg) +{ + PUNICODE_STRING pUnicode; + ANSI_STRING AnsiString; + OEM_STRING OemString; + + if (!pBuff) + return 0; + + if (!pMsg || !*pMsg) { + *pBuff = '\0'; + return 0; + } + + RtlInitString(&OemString, pMsg); + if (OemString.Length > MAX_PATH) { + OemString.Length = MAX_PATH-1; + OemString.MaximumLength = MAX_PATH; + } + AnsiString.MaximumLength = OemString.MaximumLength; + AnsiString.Buffer = pBuff; + *(AnsiString.Buffer+OemString.Length) = '\0'; + pUnicode = &NtCurrentTeb()->StaticUnicodeString; + if (!NT_SUCCESS(RtlOemStringToUnicodeString(pUnicode, + &OemString, + FALSE)) || + !NT_SUCCESS(RtlUnicodeStringToAnsiString((POEM_STRING)&AnsiString, + pUnicode, + FALSE)) ) + { + AnsiString.Length = 0; + } + + return AnsiString.Length; +} + + +/* + * Thread call back function for EnumThreadWindows + * entry: HWND hWnd - window handle to verify + * LPARAM lParam - address of edgi->hWnd == ThreadID + * + * exit: TRUE - to continue enumeration + * FALSE - edgi->hWnd has window handle for TopLevelWindow of thread + * + */ +BOOL CALLBACK GetThreadTopLevelWindow(HWND hWnd, LPARAM lParam) +{ + PDWORD pdw = (PDWORD)lParam; + + if (GetWindowThreadProcessId(hWnd, NULL) == *pdw) + { + *pdw = (DWORD)hWnd; + return FALSE; + } + return TRUE; +} + + +/* ErrorDialogBox + * + * Displays standard dialog Box for errors and warnings + * + */ +int ErrorDialogBox(char *message, char *pEdit, DWORD dwOptions) +{ + static BOOL bCalled=0; + HANDLE hThread = NULL; + HWND hWndApp; + DWORD dwThreadID, dw; + ERRORDIALOGINFO edgi; + + + if (bCalled) { // recursive call, so stop annoying the user + return RMB_IGNORE; + } + bCalled++; + + + /* Raid HotFix 3381 - alpha stress hang. All RISC implementations. + * If we leave the heartbeat generating timer hardware interrupts + * all of the time, we will continually add quick events which + * don't go off until the popup is dismissed. This will suck up + * local heap and CPU at a hipriority. + */ + SuspendTimerThread(); + + // init err dialog info + edgi.message = message; + edgi.dwReply = 0; + edgi.hWndCon = hWndConsole; + edgi.dwOptions = dwOptions; + edgi.pEdit = pEdit; + + // get window handle for the offending app + if (VDMForWOW) { + hWndApp = (HWND)GetCurrentThreadId(); + EnumWindows((WNDENUMPROC)GetThreadTopLevelWindow,(LPARAM)&hWndApp); + if (hWndApp == (HWND)GetCurrentThreadId()) { + hWndApp = HWND_DESKTOP; + } + } + else { + hWndApp = edgi.hWndCon; + } + + // + // get title of app, using DefWindowProc in lieu of + // GetWindowText to avoid callbacks into threads window proc + // + if (hWndApp == HWND_DESKTOP || + !DefWindowProc(hWndApp, WM_GETTEXT, + (WPARAM) (sizeof(edgi.Title)-1), + (LPARAM) edgi.Title) ) + { + edgi.Title[0] = '\0'; + } + + + // + // spin off a separate thread, why ? + // For DOS, to avoid suspended threads during full screen switching + // For Wow required for task termination if user chooses terminate. + // + dw = 5; + do { + hThread = CreateThread(NULL, // security + 0, // stack size + ErrorDialogBoxThread, // start address + &edgi, // thread argument + 0, // flags + &dwThreadID // gets thread ID + ); + if (hThread) + break; + else + Sleep(2000); + } while (dw--); + + if (hThread) { + do { + dw = WaitForSingleObject(hThread, 1000); + } while (dw == WAIT_TIMEOUT && !edgi.dwReply); + CloseHandle(hThread); + ResumeTimerThread(); + + + if (edgi.dwReply == RMB_ABORT) + // + // The wow termination will occur via the ErrorDialogBoxThread + // as it calls the HungAppNotifyThread. Befotrewe return give + // wow a chance to set up for termination. + // + if (VDMForWOW) { + Sleep(10); + } + + // + // If a dos app terminate now! + // + else { + TerminateVDM(); + } + } + + else { +#ifndef PROD + printf("CreateThread(ErrorDialogBoxThread) GLE=%d\n", GetLastError()); + printf("NTVDM:<%s>\n<%s>\n", edgi.Title, edgi.message ); + HostDebugBreak(); +#endif + ResumeTimerThread(); + + // + // If we can't create a thread, we are in a pretty bad way + // wow: ignore error, since not alllowed to kill WOW ssystem + // dos: terminate the VDM + // + if (!VDMForWOW) + TerminateVDM(); + } + + bCalled--; + return (int) edgi.dwReply; +} + + + + + +/* ErrorDialogBoxThread + * + * Worker routine for ErrorDialogBox. In WOW VDMs this function is + * run as its own thread. For other VDMs it is called directly. + * + * WOW: If the user chooses terminate, it will not return. + * + * exit: fills in pedgi.dwReply with ret code from DialogBoxParam + * IDB_QUIT, IDB_CONTINUE + */ +DWORD ErrorDialogBoxThread(VOID *pv) +{ + int i; + ERRORDIALOGINFO *pedgi = pv; + char *pch; + char *pLast; + + + // skip leading white space + pch = pedgi->Title; + while (*pch && !isgraph(*pch)) { + pch++; + } + + // move string to beg of buffer, strip trailing white space + i = 0; + pLast = pedgi->Title; + while (*pch) { + pedgi->Title[i++] = *pch; + if (isgraph(*pch)) { + pLast = &pedgi->Title[i]; + } + pch++; + } + *pLast = '\0'; + + + if (VDMForWOW) { + i = WowErrorDialogEvents(pedgi); + } + else { + if (pedgi->hWndCon != HWND_DESKTOP) { + SetForegroundWindow(pedgi->hWndCon); + } + + i = DialogBoxParam(GetModuleHandle(NULL), + "ERRORPANEL", + GetDesktopWindow(), + (DLGPROC) ErrorDialogEvents, + (LPARAM) pedgi + ); + } + + if (i == RMB_ABORT || i == -1) { + pedgi->dwReply = RMB_ABORT; + if (VDMForWOW && pW32HungAppNotifyThread) { + (*pW32HungAppNotifyThread)(0); // we won't return from this + } + } + else { + pedgi->dwReply = i; + } + + + return 0; +} + + + + + +LONG APIENTRY ErrorDialogEvents(HWND hDlg,WORD wMsg,LONG wParam,LONG lParam) +{ + ERRORDIALOGINFO *pedgi; + CHAR szBuff[MAX_PATH]; + int i; + LPSTR lpstr; + LONG l; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::: Process messages */ + switch(wMsg) + { + /*:::::::::::::::::::::::::::::::::::::: Initialise Dialog controls */ + case WM_INITDIALOG: + pedgi = (PERRORDIALOGINFO) lParam; + + // set the desired icon + switch (pedgi->dwOptions & (RMB_ICON_INFO | RMB_ICON_BANG | + RMB_ICON_STOP | RMB_ICON_WHAT)) + { + case RMB_ICON_STOP: lpstr = NULL; break; + case RMB_ICON_INFO: lpstr = IDI_ASTERISK; break; + case RMB_ICON_BANG: lpstr = IDI_EXCLAMATION; break; + case RMB_ICON_WHAT: lpstr = IDI_QUESTION; break; + default: lpstr = IDI_APPLICATION; break; + } + if (lpstr) { // default is STOP sign + SendDlgItemMessage(hDlg, IDE_ICON, STM_SETICON, + (WPARAM)LoadIcon(NULL,lpstr), 0); + } + + SwpButtons(hDlg, pedgi->dwOptions); + + // set Edit control message if we have one + if (pedgi->dwOptions & RMB_EDIT) { + SetWindowText(GetDlgItem(hDlg,IDE_EDIT), pedgi->pEdit); + if (*pedgi->pEdit) { + SendDlgItemMessage(hDlg, IDE_EDIT, + EM_SETSEL, + (WPARAM)0, + (LPARAM)strlen(pedgi->pEdit)); + } + SendDlgItemMessage(hDlg, IDE_EDIT, + EM_LIMITTEXT, + (WPARAM)HIWORD(pedgi->dwOptions), + (LPARAM)0); + } + else { + ShowWindow(GetDlgItem(hDlg,IDE_EDIT), SW_HIDE); + } + + // set err message text + SetWindowText(GetDlgItem(hDlg,IDE_ERRORMSG), pedgi->message); + + // set app title text + if (*pedgi->Title) { + sprintf(szBuff, + strlen(pedgi->Title) < 80 ? "\n%s" : "%s", + pedgi->Title); + SetWindowText(GetDlgItem(hDlg,IDE_APPTITLE), szBuff); + } + + SwpDosDialogs(hDlg, pedgi->hWndCon, HWND_TOPMOST, 0); + + SetWindowLong(hDlg, DWL_USER, (LONG)pedgi); + + break; + + + /*:::::::::::::::::::::::::::::::: Trap and process button messages */ + case WM_COMMAND: + pedgi = (PERRORDIALOGINFO)GetWindowLong(hDlg,DWL_USER); + i = (int) LOWORD(wParam); + switch (i) { + case IDB_QUIT: + if (pedgi->pEdit) { + *pedgi->pEdit = '\0'; + } + EndDialog(hDlg,RMB_ABORT); + break; + + case IDB_RETRY: + if (pedgi->pEdit) { + *pedgi->pEdit = '\0'; + } + EndDialog(hDlg,RMB_RETRY); + break; + + case IDCANCEL: + case IDB_CONTINUE: + if (pedgi->pEdit) { + *pedgi->pEdit = '\0'; + } + EndDialog(hDlg,RMB_IGNORE); + break; + + case IDB_OKEDIT: + if (pedgi->pEdit) { + l = SendDlgItemMessage(hDlg, IDE_EDIT, + WM_GETTEXT, + (WPARAM)HIWORD(pedgi->dwOptions), + (LPARAM)pedgi->pEdit); + if (!l) + *(pedgi->pEdit) = '\0'; + } + EndDialog(hDlg, RMB_EDIT); + break; + + default: + return(FALSE); + } + /*:::::::::::::::::::::::::::::::::::::::::: Not processing message */ + default: + return(FALSE); /* Message not processed */ + } + return TRUE; +} + + + +/* + * SwpButtons - SetWindowPos\showstate for the vraious buttons + * + * entry: HWND hDlg, - DialogBox window handle + * DWORD dwOptions + * + */ +void SwpButtons(HWND hDlg, DWORD dwOptions) +{ + RECT rect; + POINT point; + long DlgWidth, ButWidth, xOrg, xIncr, yClientPos; + WORD wButtons; + + // count number of buttons being shown + wButtons = 0; + if (dwOptions & RMB_ABORT) { + wButtons++; + } + if (dwOptions & RMB_RETRY) { + wButtons++; + } + if (dwOptions & RMB_IGNORE) { + wButtons++; + } + if (dwOptions & RMB_EDIT) { + wButtons++; + } + + // figure out where first button goes, + // and how much space between buttons + + GetWindowRect(GetDlgItem(hDlg,IDB_QUIT), &rect); + point.x = rect.left; + point.y = rect.top; + ScreenToClient(hDlg, &point); + DlgWidth = point.x; + GetWindowRect(GetDlgItem(hDlg,IDB_OKEDIT), &rect); + point.x = rect.right; + point.y = rect.top; + ScreenToClient(hDlg, &point); + DlgWidth = point.x - DlgWidth; + yClientPos = point.y; + + ButWidth = rect.right - rect.left; + xIncr = ButWidth + ButWidth/2; + + if (wButtons & 1) { // odd number of buttons + xOrg = (DlgWidth - ButWidth)/2; + if (wButtons > 1) + xOrg -= xIncr; + } + else { // even number of buttons + xOrg = DlgWidth/2 - (ButWidth + ButWidth/4); + if (wButtons == 4) + xOrg -= xIncr; + } + + + // set each of the buttons in their correct place + + + if (dwOptions & RMB_ABORT) { + SetWindowPos(GetDlgItem(hDlg,IDB_QUIT), 0, + xOrg, yClientPos, 0,0, + SWP_NOSIZE | SWP_NOZORDER); + xOrg += xIncr; + } + else { + ShowWindow(GetDlgItem(hDlg,IDB_QUIT), SW_HIDE); + } + + if (dwOptions & RMB_RETRY) { + SetWindowPos(GetDlgItem(hDlg,IDB_RETRY), 0, + xOrg, yClientPos, 0,0, + SWP_NOSIZE | SWP_NOZORDER); + xOrg += xIncr; + } + else { + ShowWindow(GetDlgItem(hDlg,IDB_RETRY), SW_HIDE); + } + + if (dwOptions & RMB_IGNORE) { + SetWindowPos(GetDlgItem(hDlg,IDB_CONTINUE), 0, + xOrg, yClientPos, 0,0, + SWP_NOSIZE | SWP_NOZORDER); + xOrg += xIncr; + } + else { + ShowWindow(GetDlgItem(hDlg,IDB_CONTINUE), SW_HIDE); + } + + if (dwOptions & RMB_EDIT) { + SetWindowPos(GetDlgItem(hDlg,IDB_OKEDIT), 0, + xOrg, yClientPos, 0,0, + SWP_NOSIZE | SWP_NOZORDER); + xOrg += xIncr; + // if we have edit control, its button is awlays + // the default button + SendMessage(hDlg, DM_SETDEFID, + (WPARAM)IDB_OKEDIT, + (LPARAM)0); + } + else { + ShowWindow(GetDlgItem(hDlg,IDB_OKEDIT), SW_HIDE); + } +} + + +/* + * SwpDosDialogs - SetWindowPos for Dos Dialogs + * + * used by Dos dialog procedures to position themselves + * relative to the current Dos session + * + * entry: HWND hDlg, - DialogBox window handle + * HWND hWndCon, - Window handle for dos session + * HWND SwpInsert, - SetWindowPos's placement order handle + * UINT SwpFlags - SetWindowPos's window positioning flags + */ +void SwpDosDialogs(HWND hDlg, HWND hWndCon, + HWND SwpInsert, UINT SwpFlags) +{ + RECT rDeskTop, rDosSess; + long DlgWidth,DlgHeight; + + GetWindowRect(GetDesktopWindow(), &rDeskTop); + GetWindowRect(hDlg, &rDosSess); + DlgWidth = rDosSess.right - rDosSess.left; + DlgHeight = rDosSess.bottom - rDosSess.top; + + + // center the dialog, if no hWnd for console + if (hWndCon == HWND_DESKTOP) { + rDosSess.left = (rDeskTop.right - DlgWidth)/2; + rDosSess.top = (rDeskTop.bottom - DlgHeight)/2; + } + // pos relative to console window, staying on screen + else { + GetWindowRect(hWndCon, &rDosSess); + rDosSess.left += (rDosSess.right - rDosSess.left - DlgWidth)/3; + if (rDosSess.left + DlgWidth > rDeskTop.right) { + rDosSess.left = rDeskTop.right - DlgWidth - GetSystemMetrics(SM_CXICONSPACING)/2; + } + if (rDosSess.left < rDeskTop.left) { + rDosSess.left = rDeskTop.left + GetSystemMetrics(SM_CXICONSPACING)/2; + } + + rDosSess.top += DlgHeight/4; + if (rDosSess.top + DlgHeight > rDeskTop.bottom) { + rDosSess.top = rDeskTop.bottom - DlgHeight - GetSystemMetrics(SM_CYICONSPACING)/2; + } + if (rDosSess.top < rDeskTop.top) { + rDosSess.top = rDeskTop.top + GetSystemMetrics(SM_CYICONSPACING)/2; + } + } + + SetWindowPos(hDlg, SwpInsert, + rDosSess.left, rDosSess.top,0,0, + SWP_NOSIZE | SwpFlags); +} + + + +/* + * WowErrorDialogEvents + * + * Uses WOWpSysErrorBox, to safely create a message box on WOW + * Replaces the functionality of the User mode DialogBox + * "ErrorDialogEvents" + */ +int WowErrorDialogEvents(ERRORDIALOGINFO *pedgi) +{ + CHAR szTitle[MAX_PATH]; + CHAR szMsg[EHS_MSG_LEN]; + USHORT wButt1, wButt2, wButt3; + + if (*pedgi->Title) { + sprintf(szMsg, "%s\n", pedgi->Title); + } + else { + szMsg[0] = '\0'; + } + + strcat(szMsg, pedgi->message); + strcat(szMsg, " "); + + if (!LoadString(GetModuleHandle(NULL), ED_WOWPROMPT, + szTitle, sizeof(szTitle) - 1)) + { + szTitle[0] = '\0'; + } + strcat(szMsg, szTitle); + + + if (!LoadString(GetModuleHandle(NULL), ED_WOWTITLE, + szTitle, sizeof(szTitle) - 1)) + { + szTitle[0] = '\0'; + } + + wButt1 = pedgi->dwOptions & RMB_ABORT ? SEB_CLOSE : 0; + wButt2 = pedgi->dwOptions & RMB_RETRY ? SEB_RETRY : 0; + wButt3 = pedgi->dwOptions & RMB_IGNORE ? SEB_IGNORE : 0; + + if (wButt1) { + wButt1 |= SEB_DEFBUTTON; + } + else if (wButt2) { + wButt1 |= SEB_DEFBUTTON; + } + else if (wButt3) { + wButt2 |= SEB_DEFBUTTON; + } + + switch (WOWpSysErrorBox(szTitle, + szMsg, + wButt1, + wButt2, + wButt3) ) + { + case 1: + return RMB_ABORT; + case 2: + return RMB_RETRY; + case 3: + return RMB_IGNORE; + } + return RMB_ABORT; +} + + + + + + + + +/*++ + * WOWpSysErrorBox + * + * 32-bit Implementation of of SysErrorBox, which doesn't exist in Win32 + * This is the only safe way to raise a message box for WOW, and is also + * safe to use for dos apps. + * + * History: + * 23-Mar-93 DaveHart Created +--*/ +ULONG WOWpSysErrorBox( + LPSTR szTitle, + LPSTR szMessage, + USHORT wBtn1, + USHORT wBtn2, + USHORT wBtn3) +{ + NTSTATUS Status; + ULONG dwParameters[4]; + ULONG dwResponse; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeTitle; + UNICODE_STRING UnicodeMessage; + + RtlInitAnsiString(&AnsiString, szTitle); + RtlAnsiStringToUnicodeString(&UnicodeTitle, &AnsiString, TRUE); + + RtlInitAnsiString(&AnsiString, szMessage); + RtlAnsiStringToUnicodeString(&UnicodeMessage, &AnsiString, TRUE); + + dwParameters[0] = ((ULONG)TRUE << 16) | (ULONG) wBtn1; + dwParameters[1] = ((ULONG)wBtn2 << 16) | (ULONG) wBtn3; + dwParameters[2] = (ULONG)&UnicodeTitle; + dwParameters[3] = (ULONG)&UnicodeMessage; + + // + // OR in 0x10000000 to force the hard error through even if + // SetErrorMode has been called. + // + + Status = NtRaiseHardError( + STATUS_VDM_HARD_ERROR | 0x10000000, + 4, + 1 << 2 | 1 << 3, + dwParameters, + 0, + &dwResponse + ); + + RtlFreeUnicodeString(&UnicodeTitle); + RtlFreeUnicodeString(&UnicodeMessage); + + return NT_SUCCESS(Status) ? dwResponse : 0; +} + + +/* + * Exported routine for wow32 to invoke a system error box + * Uses WowpSysErrorBox + */ + +ULONG WOWSysErrorBox( + LPSTR szTitle, + LPSTR szMessage, + USHORT wBtn1, + USHORT wBtn2, + USHORT wBtn3) +{ + ULONG ulRet; + + SuspendTimerThread(); + + ulRet = WOWpSysErrorBox(szTitle, + szMessage, + wBtn1, + wBtn2, + wBtn3); + + ResumeTimerThread(); + + return ulRet; +} + + + + + + + + + +#ifndef PROD +/* + * HostDebugBreak + * + * Raises a breakpoint by creating an access violation + * to give us a chance to get into a user mode debugger + * + */ +void HostDebugBreak(void) +{ + DbgBreakPoint(); +} +#endif + +VOID RcErrorBoxPrintf(UINT wId, CHAR *szMsg) +{ + CHAR message[EHS_MSG_LEN]; + CHAR acctype[EHS_MSG_LEN]; + CHAR dames[EHS_MSG_LEN]; + + + OemMessageToAnsiMessage(acctype, szMsg); + + if (LoadString(GetModuleHandle(NULL),wId, + dames, sizeof(dames)/sizeof(CHAR))) + { + sprintf(message, dames, acctype); + } + else { + strcpy(message, szDoomMsg); + } + + ErrorDialogBox(message, NULL, RMB_ICON_STOP | RMB_ABORT | RMB_IGNORE); +} diff --git a/private/mvdm/softpc.new/host/src/nt_ertbl.c b/private/mvdm/softpc.new/host/src/nt_ertbl.c new file mode 100644 index 000000000..9c0785ab1 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_ertbl.c @@ -0,0 +1,24 @@ +#include "host_def.h" +#include "insignia.h" +/*[ + Name: nt_ertbl.c + Derived From: New Development + Author: apg + Created On: 15 Apr 1991 + Sccs ID: @(#)sun4_ertbl.c 1.1 4/17/91 + Purpose: NT specific error types. + + (c)Copyright Insignia Solutions Ltd., 1991. All rights reserved. +]*/ + +static char SccsID[]="@(#)sun4_ertbl.c 1.1 4/17/91 Copyright Insignia Solutions Ltd."; + +#include "error.h" + +GLOBAL ERROR_STRUCT host_errors[] = +{ + { EH_ERROR, EV_EXTRA_CHAR }, /* FUNC_FAILED */ + { EH_ERROR, EV_EXTRA_CHAR }, /* SYSTEM ERROR */ + { EH_ERROR, EV_EXTRA_CHAR }, /* UNSUPPORT BAUD RATE */ + { EH_ERROR, 0 }, /* Error opening com port */ +}; diff --git a/private/mvdm/softpc.new/host/src/nt_event.c b/private/mvdm/softpc.new/host/src/nt_event.c new file mode 100644 index 000000000..9e746c102 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_event.c @@ -0,0 +1,1918 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Win32 Input Module. + * + * Description : This module contains data and functions that + * process Win32 messages. + * + * Author : D.A.Bartlett + * + * Notes : + */ + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdmapi.h> +#include <malloc.h> +#include <stdlib.h> +#include <excpt.h> +#include <ntddvdeo.h> +#include <ntddkbd.h> +#include <winuserp.h> +#include "conapi.h" +#include "conroute.h" +#include "insignia.h" + +#include "host_def.h" +#include "xt.h" +#include "sas.h" +#include CpuH +#include "bios.h" +#include "gvi.h" +#include "error.h" +#include "config.h" +#include "keyboard.h" +#include "keyba.h" +#include "idetect.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "nt_graph.h" +#include "nt_uis.h" +#include <stdio.h> +#include "trace.h" +#include "video.h" +#include "debug.h" +#include "ckmalloc.h" +#include "mouse.h" +#include "mouse_io.h" +#include "ica.h" + +#include "nt_mouse.h" +#include "nt_event.h" +#include "nt_vdd.h" +#include "nt_timer.h" + +#include "host.h" +#include "host_hfx.h" +#include "host_nls.h" +#include "spcfile.h" +#include "host_rrr.h" + +#include "nt_thred.h" +#include "nt_uis.h" + +#include "ntcheese.h" +#include "nt_reset.h" +#include "nt_fulsc.h" +#include <vdm.h> +#include "nt_eoi.h" +#include "nt_com.h" +#include "nt_pif.h" +#include "yoda.h" +/*================================================================ +External references. +================================================================*/ + + +// Jonle Mod +// defined in base\keymouse\keyba.c +VOID KbdResume(VOID); +VOID RaiseAllDownKeys(VOID); +int IsKeyDown(int Key); + +HANDLE hWndConsole; +HANDLE hKbdHdwMutex; +ULONG KbdHdwFull; // contains num of keys in 6805 buffer +#ifndef MONITOR +WORD BWVKey = 0; +char achES[]="EyeStrain"; +#endif +#ifdef YODA +BOOL bYoda; +#endif +BOOL stdoutRedirected=FALSE; +ULONG CntrlHandlerState=0; + +IMPORT void RestoreKbdLed(void); + + +/*::::::::::::::::::::::::::::::::::: Key history control variables/defines */ + +#define MAX_KEY_EVENTS (100) +static PKEY_EVENT_RECORD key_history_head, key_history_tail; +static PKEY_EVENT_RECORD key_history; +static key_history_count; + +int GetHistoryKeyEvent(PKEY_EVENT_RECORD LastKeyEvent, int KeyNumber); +void update_key_history(INPUT_RECORD *InputRecords, DWORD RecordsRead); +void InitKeyHistory(); +void InitQueue(void); +void ReturnUnusedKeyEvents(int UnusedKeyEvents); +int CalcNumberOfUnusedKeyEvents(void); + + +/*:::::::::::::::::::::::::::::: Local static data and defines for keyboard */ + +void nt_key_down_action(PKEY_EVENT_RECORD KeyEvent); +void nt_key_up_action(PKEY_EVENT_RECORD KeyEvent); + +void nt_process_keys(PKEY_EVENT_RECORD KeyEvent); +void nt_process_mouse(PMOUSE_EVENT_RECORD MouseEvent); +void nt_process_focus(PFOCUS_EVENT_RECORD FocusEvent); +void nt_process_menu(PMENU_EVENT_RECORD MenuEvent); +void nt_process_suspend_event(); +void nt_process_screen_scale(void); + + +// +// keyboard control state syncronization +// +KEY_EVENT_RECORD fake_shift = { TRUE, 1, VK_SHIFT, 0x2a, 0, SHIFT_PRESSED }; +KEY_EVENT_RECORD fake_caps = { TRUE, 1, VK_CAPITAL, 0x3a, 0, CAPSLOCK_ON }; +KEY_EVENT_RECORD fake_ctl = { TRUE, 1, VK_CONTROL, 0x1d, 0, 0 }; +KEY_EVENT_RECORD fake_alt = { TRUE, 1, VK_MENU, 0x38, 0, 0 }; +KEY_EVENT_RECORD fake_numlck = { TRUE, 1, VK_NUMLOCK, 0x45, 0, ENHANCED_KEY }; +KEY_EVENT_RECORD fake_scroll = { TRUE, 1, VK_SCROLL, 0x46, 0, 0}; +DWORD ToggleKeyState = NUMLOCK_ON; // default state on dos boot up + +void AltUpDownUp(void); + + +/*::::::::::::::::::::::::::::::::::: Key message passing control variables */ + +int EventStatus = ES_NOEVENTS; + +/*:::::::::::::::::::::::::::: Mouse positions and current button states */ + +BOOL SetNextMouseEvent(void); +BOOL PointerAttachedWindowed = FALSE; /* So re-attached on FS switch */ +BOOL DelayedReattachMouse = FALSE; /* but ClientRect wrong so delay attach*/ + + +#define MOUSEEVENTBUFFERSIZE (32) + +int MouseEBufNxtFreeInx; /* Index to next free entry in event buffer */ +int MouseEBufNxtEvtInx; /* Index to next event to use in mouse evt buf */ +int MouseEventCount=0; + +struct +{ + POINT mouse_pos; /* Mouse postion */ + UCHAR mouse_button_left; /* State of left button */ + UCHAR mouse_button_right; /* State of right button */ +} MouseEventBuffer[MOUSEEVENTBUFFERSIZE]; + + +ULONG NoMouseTics; + +ULONG event_thread_blocked_reason = 0xFFFFFFFF; + + +HCURSOR cur_cursor = NULL; /* Current cursor handle */ +#ifdef X86GFX +half_word saved_text_lines; /* No of lines for last SelectMouseBuffer. */ +#endif /* X86GFX */ + + +/*@ACW======================================================================== +Flag to keep track of whether or not the Hide Pointer system menu item is +greyed (i.e. the window is iconised) or enabled. +============================================================================*/ +BOOL bGreyed=FALSE; + + +/*::::::::::::::::::::::::::::: Variables used to control key message Queue */ + +#define KEY_QUEUE_SIZE (25) + +typedef struct { BYTE ATcode; BOOL UpKey; } KeyQEntry; + +typedef struct +{ + short KeyCount; /* Number of keys in the queue */ + short QHead; /* Head of queue */ + short QTail; /* Tail of queue */ + KeyQEntry Keys[KEY_QUEUE_SIZE]; /* Keys in queue */ +} KeyQueueData; + +static KeyQueueData KeyQueue; + + + + +static volatile BOOL InitComplete; + +/*:::::: Variables used to control blocking and unblocking the event thread */ + +BOOL fEventThreadBlock = FALSE; /* Event thread blocked ??? */ +HANDLE hConsoleWait; /* Console block mutex */ +HANDLE hConsoleWaitStall; /* Object used to sync threads on block */ +HANDLE hConsoleSuspend; +/*::::::::::::: Variable to hold current screen scale ::::::::::::::::::::::*/ + +int savedScale; + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Local functions */ + +DWORD nt_event_loop(void); +BOOL CntrlHandler(ULONG CtrlType); +void send_up_keys(void); + + +VOID ReturnBiosBufferKeys(VOID); +DWORD ConsoleEventThread(PVOID pv); + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Start event processing thread ::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_start_event_thread(void) +{ + // + // create kbd hardware mutex and kbd not full event + // + if(!(hKbdHdwMutex = CreateMutex(NULL, FALSE, NULL))) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + // + // Create Event Thread, + // events to block\resume console input + // event queue + // + // The Event Thread is created suspended to prevent us + // from receiving input before the DOS is ready + // + if (!VDMForWOW) { + + // + // Register Control 'C' handler, for DOS only + // + if(!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CntrlHandler,TRUE)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + ThreadInfo.EventMgr.Handle = CreateThread(NULL, + 8192, + ConsoleEventThread, + NULL, + CREATE_SUSPENDED, + &ThreadInfo.EventMgr.ID); + + if(!ThreadInfo.EventMgr.Handle) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + if(!(hConsoleWait = CreateEvent(NULL, FALSE, FALSE, NULL))) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + if(!(hConsoleWaitStall = CreateEvent(NULL, FALSE, FALSE, NULL))) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + if(!(hConsoleSuspend = CreateEvent(NULL, FALSE, FALSE, NULL))) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + + InitQueue(); + check_malloc(key_history,MAX_KEY_EVENTS,KEY_EVENT_RECORD); + InitKeyHistory(); + } + + return; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Start event processing thread ::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_remove_event_thread(void) +{ + /* Must make sure that the thread has terminated */ + if (!VDMForWOW && ThreadInfo.EventMgr.Handle) { + NtAlertThread(ThreadInfo.EventMgr.Handle); + } +} + + + + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::: Process events ::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +DWORD ConsoleEventThread(PVOID pv) +{ + + DWORD dwRet = (DWORD)-1; + + try { + + SetThreadPriority(ThreadInfo.EventMgr.Handle, THREAD_PRIORITY_HIGHEST); + DelayMouseEvents(2); + + dwRet = nt_event_loop(); + + CloseHandle(ThreadInfo.EventMgr.Handle); + CloseHandle(hConsoleWait); + CloseHandle(hConsoleSuspend); + ThreadInfo.EventMgr.Handle = NULL; + ThreadInfo.EventMgr.ID = 0; + } + except(VdmUnhandledExceptionFilter(GetExceptionInformation())) { + ; // we shouldn't arrive here + } + + return dwRet; +} + + + +DWORD nt_event_loop(void) +{ + DWORD RecordsRead; + DWORD loop; + NTSTATUS status; + HANDLE Events[2]; + + /* + * The con server is optimized to avoid extra CaptureBuffer allocations + * when the number of InputRecords is less than "INPUT_RECORD_BUFFER_SIZE". + * Currently INPUT_RECORD_BUFFER_SIZE is defined internally to the + * con server as Five records. See ntcon\client\iostubs.c. + */ + + INPUT_RECORD InputRecord[5]; + + + /* the console input handle shouldn't get changed during the lifetime + of the ntvdm + */ + Events[0] = GetConsoleInputWaitHandle(); ////sc.InputHandle + Events[1] = hConsoleSuspend; + /*:::::::::::::::::::::::::::::::::::::::::::::: Get and process events */ + + while (TRUE) { + + // + // Wait for the InputHandle to be signalled, or a suspend event. + // + status = NtWaitForMultipleObjects(2, + Events, + WaitAny, + TRUE, + NULL + ); + + // + // Input handle was signaled, Read the input, without + // waiting (otherwise we may get blocked and be unable to + // handle the suspend event). + // + if (!status) { + if (ReadConsoleInputExW(sc.InputHandle, + &InputRecord[0], + sizeof(InputRecord)/sizeof(INPUT_RECORD), + &RecordsRead, + CONSOLE_READ_NOWAIT + )) + { + if (!RecordsRead) { + continue; + } + + update_key_history(&InputRecord[0], RecordsRead); + } + else { + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + break; //Read from console failed + } + } + + // + // Console Suspend event was signaled + // + else if (status == 1) { + nt_process_suspend_event(); + continue; + } + + // + // alerted or User apc, This means to terminate + // Got an error, inform the user. + // + else { + if (!NT_SUCCESS(status)) { + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + } + return 0; + } + + + // + // Process the Input Events + // + for (loop = 0; loop < RecordsRead; loop++) { + switch(InputRecord[loop].EventType) { + + case MOUSE_EVENT: + nt_process_mouse(&InputRecord[loop].Event.MouseEvent); + break; + + + case KEY_EVENT: + + if (WaitKbdHdw(0x50000)) { + return(0); + } + + do { + + if (KbdHdwFull > 8) { + ULONG Delay = KbdHdwFull; + + HostReleaseKbd(); + HostIdleNoActivity(); + Sleep(Delay); + if (WaitKbdHdw(0x50000)) + return (0); + } + + nt_process_keys(&InputRecord[loop].Event.KeyEvent); + + } while (++loop < RecordsRead && + InputRecord[loop].EventType == KEY_EVENT); + loop--; + HostReleaseKbd(); + HostIdleNoActivity(); + break; + + case MENU_EVENT: + nt_process_menu(&InputRecord[loop].Event.MenuEvent); + break; + + + case FOCUS_EVENT: + nt_process_focus(&InputRecord[loop].Event.FocusEvent); + break; + + case WINDOW_BUFFER_SIZE_EVENT: + nt_mark_screen_refresh(); + break; + + default: + fprintf(trace_file,"Undocumented event from console\n"); + break; + } + } + + // + // encourage the console to pack events together + // + + Sleep(10); + + } + + return 0; +} + + +/*:::::::::::::::::::::: Update key history buffer ::::::::::::::::::::::::*/ + +void update_key_history(register INPUT_RECORD *InputRecords, + register DWORD RecordsRead) +{ + for(;RecordsRead--;InputRecords++) + { + if(InputRecords->EventType == KEY_EVENT) + { + + //Transfer key event to history buffer + *key_history_tail = InputRecords->Event.KeyEvent; + + //Update ptrs to history buffer + + if(++key_history_tail >= &key_history[MAX_KEY_EVENTS]) + key_history_tail = key_history; + + //Check for buffer overflow + + if(key_history_tail == key_history_head) + { + //Buffer overflow, bump head ptr and loss oldest key + + if(++key_history_head >= &key_history[MAX_KEY_EVENTS]) + key_history_head = key_history; + } + + //Update history counter + + if(key_history_count != MAX_KEY_EVENTS) + key_history_count++; + } + } + return; +} + +/*:::::::::::::::: Remove last key added to key history buffer ::::::::::::::*/ + +int GetHistoryKeyEvent(PKEY_EVENT_RECORD LastKeyEvent, int KeyNumber) +{ + int KeyReturned = FALSE; + int KeysBeforeWrap = key_history_tail-key_history; + + if(key_history_count >= KeyNumber) + { + if(KeysBeforeWrap < KeyNumber) + { + //Wrap + + *LastKeyEvent = key_history[MAX_KEY_EVENTS - + (KeyNumber - KeysBeforeWrap)]; + } + else + { + //No warp + *LastKeyEvent = key_history_tail[0-KeyNumber]; + } + + KeyReturned = TRUE; + } + + return(KeyReturned); +} + +/*:::::::::::::::::::: Init key history buffer ::::::::::::::::::::::::::::::*/ + +void InitKeyHistory() +{ + key_history_head = key_history_tail = key_history; + key_history_count = 0; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Process menu events :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_process_focus(PFOCUS_EVENT_RECORD FocusEvent) +{ + + BOOL slow; + + sc.Focus = FocusEvent->bSetFocus; + + if(sc.Focus ) + { + /* input focus acquired */ + AltUpDownUp(); + + MouseInFocus(); + if (PointerAttachedWindowed && sc.ScreenState == WINDOWED) + { + MouseHide(); + PointerAttachedWindowed = FALSE; /* only used in switch */ + DelayedReattachMouse = TRUE; + } + /* set the event in case waiting for focus to go fullscreen */ + if(sc.FocusEvent != NULL) PulseEvent(sc.FocusEvent); +#ifndef MONITOR + if (sc.ModeType == GRAPHICS) + host_mark_screen_refresh(); +#endif + } + else /* input focus lost */ + { + + slow = savedScreenState != sc.ScreenState; + + MouseOutOfFocus(); /* turn off mouse 'attachment' */ + +#ifndef PROD + fprintf(trace_file,"Focus lost\n"); +#endif + } + + + +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Process menu events :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +void nt_process_menu(PMENU_EVENT_RECORD MenuEvent) +{ + +/*================================================================ +Code to handle the event resulting from the user choosing the +Settings... menu option from the system menu. + +Andrew Watson 6/2/92 +Ammended to do the mouse attach/detach menu stuff 26/8/92 +Ammended to do Alt key processing. +12-Apr-1994 Jonle fixed key processing + +================================================================*/ + + switch(MenuEvent->dwCommandId) + { + // consrv sends when it gets an initmenu, and indicates + // that a sys menu is coming up, and we are losing kbd focus + case WM_INITMENU: + AltUpDownUp(); + /* stop cursor cliping */ + MouseSystemMenuON(); + break; + + // consrv sends when it gets a MENUSELECT with + // HIWORD(wParam) == MF_MAINMENU (0xffff). I think + // it means we are regaining kbd focus + case WM_MENUSELECT: + MouseSystemMenuOFF(); + break; + + case IDM_POINTER: + { + BOOL bIcon; + + VDMConsoleOperation(VDM_IS_ICONIC,&bIcon); + + /* is the SoftPC window NOT an icon? */ + if(!bIcon) + { + if(bPointerOff) /* if the pointer is not visible */ + { + MouseDisplay(); + } + else/* hide the pointer */ + { + MouseHide(); + } + } + break; + } + + } /* End of switch */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Process suspend event thread event ::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_process_suspend_event() +{ + NTSTATUS Status; + + //Tell the CPU thread that we have blocked + SetEvent(hConsoleWaitStall); + + // + // Wait for the resume routine to wake us up + // + Status = NtWaitForSingleObject(hConsoleWait, TRUE, NULL); + + // If error, probably cause handle was closed, so exit + // if alerted signal to exit + if (Status) { + ExitThread(0); + } +} + + + +/* + * Resets the vdm's toggle key state according to the + * Current incoming key state from console by sending + * fake keys to the vdm as needed. + * the caller must be holding the keyboard mutex. + */ + +void SyncToggleKeys(WORD wVirtualKeyCode, DWORD dwControlKeyState) +{ + DWORD CurrKeyState; + + CurrKeyState = dwControlKeyState; + + // + // If the key is one of the toggles, and changed state + // invert the current state, since want we really want + // is the toggle state before this key was pressed. + // + if (wVirtualKeyCode == VK_SHIFT && + (CurrKeyState & SHIFT_PRESSED) != (ToggleKeyState & SHIFT_PRESSED)) + { + CurrKeyState ^= SHIFT_PRESSED; + } + + if (wVirtualKeyCode == VK_NUMLOCK && + (CurrKeyState & NUMLOCK_ON) != (ToggleKeyState & NUMLOCK_ON)) + { + CurrKeyState ^= NUMLOCK_ON; + } + + if (wVirtualKeyCode == VK_SCROLL && + (CurrKeyState & SCROLLLOCK_ON) != (ToggleKeyState & SCROLLLOCK_ON)) + { + CurrKeyState ^= SCROLLLOCK_ON; + } + + if (wVirtualKeyCode == VK_CAPITAL && + (CurrKeyState & CAPSLOCK_ON) != (ToggleKeyState & CAPSLOCK_ON)) + { + /* + * KbdBios does not toggle capslock if Ctl is down. + * Nt does the opposite always toggling capslock state. + * Force NT conform behaviour by sending: + * Ctl up, Caps Dn, Caps Up, Ctl dn + * so that KbdBios will toggle its caps state + * before processing the current Ctl-Caps keyevent. + */ + if (dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) + { + nt_key_up_action(&fake_ctl); + if (IsKeyDown(30)) { // capslock + nt_key_up_action(&fake_caps); + } + nt_key_down_action(&fake_caps); + nt_key_up_action(&fake_caps); + nt_key_down_action(&fake_ctl); + } + + CurrKeyState ^= CAPSLOCK_ON; + } + + + if ((CurrKeyState & SHIFT_PRESSED) && + !(ToggleKeyState & SHIFT_PRESSED)) + { + nt_key_down_action(&fake_shift); + } + else if ((CurrKeyState & SHIFT_PRESSED) && + !(ToggleKeyState & SHIFT_PRESSED) ) + { + nt_key_up_action(&fake_shift); + } + + + if ((CurrKeyState & NUMLOCK_ON) != (ToggleKeyState & NUMLOCK_ON)) + { + if (IsKeyDown(90)) { + nt_key_up_action(&fake_numlck); + } + nt_key_down_action(&fake_numlck); + nt_key_up_action(&fake_numlck); + } + + if ((CurrKeyState & CAPSLOCK_ON) != (ToggleKeyState & CAPSLOCK_ON)) + { + if (IsKeyDown(30)) { // capslock + nt_key_up_action(&fake_caps); + } + nt_key_down_action(&fake_caps); + nt_key_up_action(&fake_caps); + } + + if ((CurrKeyState & SCROLLLOCK_ON) != (ToggleKeyState & SCROLLLOCK_ON)) + { + if (IsKeyDown(125)) { // scrolllock + nt_key_up_action(&fake_scroll); + } + nt_key_down_action(&fake_scroll); + nt_key_up_action(&fake_scroll); + } +} + + + + +/* + * AltUpDownUp - Ensures all kbdhdw keys are in the up state + * + * Does handling for CW apps with alt triggerred menus + * to force them out of the menu state. + * + * This works for ALT-Esc, Alt-Enter, Alt-Space because we + * we haven't received an Alt-up when we receive the lose focus + * event. (We actually never receive the alt-up). Thus we can + * detect when a dos app might be in its alt triggered menu. + * + * Alt-TAB does not work, because user32 got ?smart? and sends an + * alt-up before switching focus, breaking our detection algorithm. + * Also other hot keys which are meaning ful to various dos apps + * are not handled. Note that this is the same detection algorithm + * used by win 3.1. + * + */ +void AltUpDownUp(void) +{ + + Sleep(100); + if (WaitKbdHdw(0xffffffff)) + return; + + if (IsKeyDown(60) || IsKeyDown(62)) { // left alt, right alt + + nt_key_up_action(&fake_alt); // Alt Up + + HostReleaseKbd(); + Sleep(100); + if (WaitKbdHdw(0xffffffff)) + ExitThread(1); + + nt_key_down_action(&fake_alt); // Alt Down + + HostReleaseKbd(); + Sleep(100); + if (WaitKbdHdw(0xffffffff)) + ExitThread(1); + + nt_key_up_action(&fake_alt); // Alt Up + + HostReleaseKbd(); + Sleep(20); + if (WaitKbdHdw(0xffffffff)) + ExitThread(1); + + } + + RaiseAllDownKeys(); + + HostReleaseKbd(); + +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Process event, Class registered message handler :::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#define TOGGLEKEYBITS (SHIFT_PRESSED | NUMLOCK_ON | SCROLLLOCK_ON | CAPSLOCK_ON) + +VOID nt_process_keys(PKEY_EVENT_RECORD KeyEvent) +{ + + // Check the last toggle key states, for change + if ((ToggleKeyState & TOGGLEKEYBITS) + != (KeyEvent->dwControlKeyState & TOGGLEKEYBITS)) + { + SyncToggleKeys(KeyEvent->wVirtualKeyCode, KeyEvent->dwControlKeyState); + ToggleKeyState = KeyEvent->dwControlKeyState & TOGGLEKEYBITS; + } + + /*............................... Maintain shift states in case of pastes */ + + if(KeyEvent->bKeyDown) { + + +#ifndef MONITOR + // + // Check for windowed graphics resize + // + if (BWVKey && (KeyEvent->wVirtualKeyCode == BWVKey)) + { + nt_process_screen_scale(); + } +#endif + + + switch(KeyEvent->wVirtualKeyCode) { +#ifdef YODA + case VK_F11: + if (getenv("YODA")) { + EventStatus |= ~ES_YODA; + } + break; +#endif + + case VK_SHIFT: + fake_shift = *KeyEvent; + break; + + case VK_MENU: + fake_alt = *KeyEvent; + break; + + case VK_CONTROL: + fake_ctl = *KeyEvent; + break; + } + + nt_key_down_action(KeyEvent); + + } else { /* ! KeyEvent->bKeyDown */ + + /* + * We don't get a CTRL-Break key make code cause console + * eats it when it invokes the CntrlHandler. We must fake + * it here, rather than in the CntrlHandler, cause + * CntrlHandler is asynchronous and we may lose the state + * of the Cntrl-Key. + * 25-Aug-1992 Jonle + * Also SysRq/Printscreen key. Simon May 93 + */ + if (KeyEvent->wVirtualKeyCode == VK_CANCEL || + KeyEvent->wVirtualKeyCode == VK_SNAPSHOT ) + { + nt_key_down_action(KeyEvent); + } + + nt_key_up_action(KeyEvent); /* Key up */ + + } /* ! KeyEvent->bKeyDown */ + +} /* nt_process_keys */ + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Process key down event :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_key_down_action(PKEY_EVENT_RECORD KeyEvent) +{ + BYTE ATcode; + + ATcode = KeyMsgToKeyCode(KeyEvent); + + if(ATcode) + (*host_key_down_fn_ptr)(ATcode); + +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Process keyup event ::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_key_up_action(PKEY_EVENT_RECORD KeyEvent) +{ + BYTE ATcode; + + ATcode = KeyMsgToKeyCode(KeyEvent); + + if(ATcode) + (*host_key_up_fn_ptr)(ATcode); + +} + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Process mouse button and movement events :::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + + +void nt_process_mouse(PMOUSE_EVENT_RECORD MouseEvent) +{ + int LastMouseInx; + POINT mouse_pos; + UCHAR mouse_button_left, mouse_button_right; + + host_ica_lock(); + + if (NoMouseTics) { + ULONG CurrTic; + CurrTic = NtGetTickCount(); + if (CurrTic > NoMouseTics || + (NoMouseTics == 0xffffffff && CurrTic < (0xffffffff >> 1)) ) + { + NoMouseTics = 0; + MouseEBufNxtEvtInx = MouseEBufNxtFreeInx = 0; + } + else { + host_ica_unlock(); + return; + } + } + + + /*:::::::::::::::::::::::::::::::::::::::::::::::::: Setup button state */ + + mouse_button_left = MouseEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED + ? 1 : 0; + + mouse_button_right = MouseEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED + ? 1 : 0; + + /*::::::::::::::::::::::::::::::::::::::::::::::: Get new mouse postion */ + + mouse_pos.x = MouseEvent->dwMousePosition.X; /* Mouse X */ + mouse_pos.y = MouseEvent->dwMousePosition.Y; /* Mouse Y */ + + /* + * Fix for the case where mouse events are still delivered when the cursor + * is outside the window because one of the mouse buttons is down. This can + * cause negative numbers in mouse_pos which can cause divide overflow in + * mouse interrupt handler code. + */ +#ifdef X86GFX + if (sc.ScreenState == WINDOWED) +#endif /* X86GFX */ + { + ULONG maxWidth = sc.PC_W_Width, + maxHeight = sc.PC_W_Height; + + if ((sc.ModeType == TEXT) && get_pix_char_width() && + get_host_char_height()) + { + maxWidth /= get_pix_char_width(); + maxHeight /= get_host_char_height(); + } + if (mouse_pos.x < 0) + mouse_pos.x = 0; + else if ((ULONG)mouse_pos.x >= maxWidth) + mouse_pos.x = maxWidth - 1; + if (mouse_pos.y < 0) + mouse_pos.y = 0; + else if ((ULONG)mouse_pos.y >= maxHeight) + mouse_pos.y = maxHeight - 1; + } + + + LastMouseInx = MouseEBufNxtFreeInx ? MouseEBufNxtFreeInx - 1 + : MOUSEEVENTBUFFERSIZE - 1; + + // + // If the previous mouse event is the same as the last + // then drop the event. + // + if (MouseEBufNxtEvtInx != MouseEBufNxtFreeInx && + MouseEventBuffer[LastMouseInx].mouse_pos.x == mouse_pos.x && + MouseEventBuffer[LastMouseInx].mouse_pos.y == mouse_pos.y && + MouseEventBuffer[LastMouseInx].mouse_button_left == mouse_button_left && + MouseEventBuffer[LastMouseInx].mouse_button_right == mouse_button_right ) + { + host_ica_unlock(); + return; + } + + + // + // If not too many events in the mouse buffer + // or no outstanding mouse events + // or the mouse button state has changed. + // Add the current mouse data to the next free position in + // the MouseEventBuffer + // + + + if(MouseEventCount <= MOUSEEVENTBUFFERSIZE/2 || + MouseEBufNxtEvtInx == MouseEBufNxtFreeInx || + MouseEventBuffer[LastMouseInx].mouse_button_left != mouse_button_left || + MouseEventBuffer[LastMouseInx].mouse_button_right != mouse_button_right) + + { + LastMouseInx = MouseEBufNxtFreeInx; + if(++MouseEBufNxtFreeInx == MOUSEEVENTBUFFERSIZE) { + MouseEBufNxtFreeInx = 0; + } + + MouseEventCount++; + + // + // if the buffer is full drop the oldest event + // + if (MouseEBufNxtFreeInx == MouseEBufNxtEvtInx) { + always_trace0("Mouse event input buffer overflow"); + if(++MouseEBufNxtEvtInx == MOUSEEVENTBUFFERSIZE) + MouseEBufNxtEvtInx = 0; + } + } + + + MouseEventBuffer[LastMouseInx].mouse_pos = mouse_pos; + MouseEventBuffer[LastMouseInx].mouse_button_left = mouse_button_left; + MouseEventBuffer[LastMouseInx].mouse_button_right = mouse_button_right; + + DoMouseInterrupt(); + + host_ica_unlock(); +} + + +/* MoreMouseEvents - returns TRUE if there are more mousevents + * to be retrieved. + * + * Assumes caller has the IcaLock + */ +BOOL MoreMouseEvents(void) +{ + return MouseEBufNxtEvtInx != MouseEBufNxtFreeInx; +} + + +/* + * GetNextMouseEvent - copies the next available Mouse Event to + * the global data structure os_pointer. if there are no new events + * nothing is copied. + * + * Assumes caller has the IcaLock + */ +void GetNextMouseEvent(void) +{ + + if (MouseEBufNxtEvtInx != MouseEBufNxtFreeInx) { + os_pointer_data.x = (SHORT)MouseEventBuffer[MouseEBufNxtEvtInx].mouse_pos.x; + os_pointer_data.y = (SHORT)MouseEventBuffer[MouseEBufNxtEvtInx].mouse_pos.y; + os_pointer_data.button_l = MouseEventBuffer[MouseEBufNxtEvtInx].mouse_button_left; + os_pointer_data.button_r = MouseEventBuffer[MouseEBufNxtEvtInx].mouse_button_right; + + if (++MouseEBufNxtEvtInx == MOUSEEVENTBUFFERSIZE) + MouseEBufNxtEvtInx = 0; + + MouseEventCount--; + } + +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::Flush all outstanding mouse events :::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void FlushMouseEvents(void) +{ + host_ica_lock(); + MouseEBufNxtEvtInx = MouseEBufNxtFreeInx = 0; + host_ica_unlock(); +} + +// +// count == ticks to throwaway, mouse events +// +VOID DelayMouseEvents(ULONG count) +{ + host_ica_lock(); + + NoMouseTics = NtGetTickCount(); + count = 110 *(count+1); + count = NoMouseTics + count; + if (count > NoMouseTics) + NoMouseTics = count; + else + NoMouseTics = 0xffffffff; // wrap! + + MouseEBufNxtEvtInx = MouseEBufNxtFreeInx = 0; + host_ica_unlock(); +} + + +#ifndef X86GFX +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::: Process screen scale event :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_process_screen_scale(void) +{ + SAVED BOOL init = FALSE; + + + host_ica_lock(); + if (!init) + { + init = TRUE; + savedScale = get_screen_scale(); + } + if (savedScale == 4) + savedScale = 2; + else + savedScale++; + EventStatus |= ES_SCALEVENT; + host_ica_unlock(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: See if there is a scale event and if so return the new scale :::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +GLOBAL void GetScaleEvent(void) +{ + int Scale; + + if (EventStatus & ES_SCALEVENT) + { + host_ica_lock(); + Scale = savedScale; + EventStatus &= ~ES_SCALEVENT; + host_ica_unlock(); + host_set_screen_scale(Scale); + } +} +#endif + + +#ifdef YODA +void CheckForYodaEvents(void) +{ + static HANDLE YodaEvent = NULL; + + /*:::::::::::::::::::::::::::::::::: check for Yoda event object signal */ + + if(YodaEvent == NULL) + { + if((YodaEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,"YodaEvent")) == NULL) + { + always_trace0("Failed to open Yoda event object\n"); + YodaEvent = (HANDLE) -1; + } + } + + if(YodaEvent && YodaEvent != (HANDLE) -1) + { + if(!WaitForSingleObject(YodaEvent,0)) + { + ResetEvent(YodaEvent); + Enter_yoda(); + } + } + + // check for yoda kbd event + if (EventStatus & ES_YODA) { + EventStatus &= ~ES_YODA; + Enter_yoda(); + } + +} +#endif + + +// Host funcs to support base keyboard Mods. (Prevents Windows calls from +// appearing in base). +/* WaitKbdHdw + * + * Synchronizes access to kbd hardware + * between event thread and cpu thread + * + * entry: DWORD dwTimeOut - Millisecs to wait + * + * exit: DWORD dwRc - return code from WaitForSingleObject() + * + */ +DWORD WaitKbdHdw(DWORD dwTime) +{ + DWORD dwRc, dwErr; + + dwErr = dwRc = WaitForSingleObject(hKbdHdwMutex, dwTime); + if (dwRc == WAIT_TIMEOUT) { + if (dwTime < 0x10000) { + dwErr = 0; + } + } + else if (dwRc == 0xFFFFFFFF) { + dwErr = GetLastError(); + } + + if (dwErr) { + DisplayErrorTerm(EHS_FUNC_FAILED,dwErr,__FILE__,__LINE__); + } + + return dwRc; +} + +GLOBAL VOID HostReleaseKbd(VOID) +{ + ReleaseMutex(hKbdHdwMutex); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Register new cursor :::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void RegisterDisplayCursor(HCURSOR newC) +{ + cur_cursor = newC; + //if(GetFocus() == sc.Display) SetCursor(newC); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::: Initialise event queue :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void InitQueue(void) +{ + /*:::::::::::::::::::::::::::::: Initialise key queue control variables */ + + KeyQueue.KeyCount = KeyQueue.QHead = KeyQueue.QTail = 0; + EventStatus = ES_NOEVENTS; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Control handler */ + +BOOL CntrlHandler(ULONG CtrlType) +{ + switch (CtrlType) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + break; + + case SYSTEM_ROOT_CONSOLE_EVENT: + // + // top most console process is going away + // remember this so we will terminate the vdm in + // nt_block_event, when the dos app voluntarily exits + // + CntrlHandlerState |= CNTRL_SYSTEMROOTCONSOLE; + + // fall thru to see if we should terminate now + + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: +#ifndef PROD + if (VDMForWOW) { // shouldn't happen + printf("WOW: Received EndTask Notice, but we shouldn't\n"); + break; + } +#endif + if (CntrlHandlerState & CNTRL_PUSHEXIT) { + ExitProcess(0); + return FALSE; + } + + if ( (CntrlHandlerState & CNTRL_PIFALLOWCLOSE) || + (!(CntrlHandlerState & CNTRL_SHELLCOUNT) && + (CntrlHandlerState & CNTRL_VDMBLOCKED)) ) + { + TerminateVDM(); + return FALSE; + } + + break; + +#ifndef PROD + default: // shouldn't happen + printf("NTVDM: Received unknown CtrlType=%lu\n",CtrlType); +#endif + } + return TRUE; +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::: Functions to block/resume the event thread :::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Currently param is only used to indicate whether the command is exiting but + * the PIF setting shows window should not close. + */ + + void nt_block_event_thread(ULONG BlockFlags) + { + DWORD dw; + int UnusedKeyEvents; + COORD scrSize; + + nt_init_event_thread(); // does nothing if init already + + /* remember the reason why we are blocked. + * 0 == the application is not being terminated, instead, it is + * executing either a 32 bits application or command.com(TSR installed + * or shell out). + * 1 == application is terminating. + * if the application is terminating, we are safe to re-enable + * stream io on nt_resume_event_thread. + */ + event_thread_blocked_reason = BlockFlags; + + // Send notification message for VDDs */ + VDDBlockUserHook(); + + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Turn off sound */ + InitSound(FALSE); + + /*::::::::::::::::::::::::::::::::::::::::::::: Block the event thread */ + + if (!VDMForWOW) { + + ResetMouseOnBlock(); // remove mouse pointer menu item + + SetEvent(hConsoleSuspend); + + //Wait for the event thread to block + dw = WaitForSingleObject(hConsoleWaitStall, 360000); + if (dw) { + if (dw == WAIT_TIMEOUT) + SetLastError(ERROR_SERVICE_REQUEST_TIMEOUT); + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + TerminateVDM(); + } + + + /*::::::::::::::::::::::::::::::::: Flush screen output, reset console */ + + + if (sc.ScreenState == STREAM_IO) + stream_io_update(); + else { + if (sc.ScreenState != FULLSCREEN) + (*update_alg.calc_update)(); + // Put Console back the way it was when we started up + ResetConsoleState(); + + // Ensure system pointer visible. + while(ShowConsoleCursor(sc.OutputHandle,TRUE) < 0) + ; + +#ifdef MONITOR + if(sc.ScreenState == FULLSCREEN) RegainRegenMemory(); +#endif + + /* If keeping window open when exiting and fullscreen, return to desktop */ + /* Transition made simple as VDM de-registered from console */ + if (BlockFlags == 1 && sc.ScreenState == FULLSCREEN) + { + SetConsoleDisplayMode(sc.OutputHandle, CONSOLE_WINDOWED_MODE, &scrSize); + } + } + + // Turn off PIF Reserved & ShortCut Keys + DisablePIFKeySetup(); + + + /*::: Push unused key events from kbd hardware back into the console */ + + UnusedKeyEvents = CalcNumberOfUnusedKeyEvents(); + + ReturnUnusedKeyEvents(UnusedKeyEvents); + + /*::: Push unused keys from 16 bit bios buffer back into the console */ + ReturnBiosBufferKeys(); + + /*::: Flush outstanding mouse events */ + + FlushMouseEvents(); + + /*::: Restore Console modes */ + + if(!SetConsoleMode(sc.InputHandle,sc.OrgInConsoleMode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + + if(!SetConsoleMode(sc.OutputHandle,sc.OrgOutConsoleMode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + + if (!(CntrlHandlerState & CNTRL_SHELLCOUNT) && + CntrlHandlerState & CNTRL_SYSTEMROOTCONSOLE) { + TerminateVDM(); + } + // + // Reset the Active buffer field in sc. + // + sc.ActiveOutputBufferHandle = sc.OutputHandle; + MouseDetachMenuItem(FALSE); + } + + // clear kbd state flags in biosdata area + sas_store (kb_flag,0); + sas_store (kb_flag_1,0); + sas_store (kb_flag_2,0); + sas_store (kb_flag_3,KBX); + sas_store (alt_input,0); + + + /*::: Suspend timer thread */ + + SuspendTimerThread(); + + + /*::: Close printer ports and comms ports */ + + host_lpt_close_all(); /* Close all open printer ports */ + + if (!(CntrlHandlerState & CNTRL_SHELLCOUNT)) + host_com_close_all(); /* Close all open comms ports */ + + fEventThreadBlock = TRUE; + + CntrlHandlerState |= CNTRL_VDMBLOCKED; +#ifndef PROD + fprintf(trace_file,"Blocked event thread\n"); +#endif + +} + +/*::::::::::::::::::::::::::::::::::::: Resume event and heart beat threads */ + +void nt_resume_event_thread(void) +{ + IMPORT DWORD TlsDirectError; //Direct access 'used' flag + + // + // If wow enters here we are in a really bad way + // since it means they are trying to reload + // + if (VDMForWOW) { + TerminateVDM(); + return; + } + + /* re-enable stream io if the application is terminating */ + + if (event_thread_blocked_reason == 1 && + StreamIoSwitchOn && !host_stream_io_enabled) { + /* renew the screen buffer and window size */ + if (!GetConsoleScreenBufferInfo(sc.OutputHandle, + &sc.ConsoleBuffInfo)) + + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + + enable_stream_io(); +#ifdef X86GFX + /* tell video bios we are back to stream io */ + sas_store_no_check( (int10_seg<<4)+useHostInt10, STREAM_IO); +#endif + + } + nt_init_event_thread(); // does nothing if init already + + CntrlHandlerState &= ~CNTRL_VDMBLOCKED; +#ifndef PROD + fprintf(trace_file,"Resume event thread\n"); +#endif + + // Setup Console modes + SetupConsoleMode(); + + // Turn PIF Reserved & ShortCut Keys back on + EnablePIFKeySetup(); + + // + // re-enable direct access error panels. + TlsSetValue(TlsDirectError, 0); + + ica_reset_interrupt_state(); + + // Send notification message for VDDs */ + VDDResumeUserHook(); + + if (sc.ScreenState != STREAM_IO) { + DoFullScreenResume(); + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + } + ResumeTimerThread(); /* Restart timer thread */ + + // set kbd state flags in biosdata area + if (!VDMForWOW) { + SyncBiosKbdLedToKbdDevice(); + } + + KbdResume(); + + SetEvent(hConsoleWait); /* Restart event thread */ +} + + + +void +SyncBiosKbdLedToKbdDevice( + void + ) +{ + NTSTATUS Status; + UNICODE_STRING UnicodeString; + OBJECT_ATTRIBUTES ObjAttr; + IO_STATUS_BLOCK IoStatus; + KEYBOARD_INDICATOR_PARAMETERS kip; + KEYBOARD_UNIT_ID_PARAMETER kuid; + HANDLE hKeyboard = 0; + HANDLE KeyboardEvent = 0; + ULONG ControlKeyState; + + unsigned char KbdLed; + + + ControlKeyState = ToggleKeyState & (CAPSLOCK_ON | NUMLOCK_ON | SCROLLLOCK_ON); + + RtlInitUnicodeString(&UnicodeString, DD_KEYBOARD_DEVICE_NAME_U L"0"); + InitializeObjectAttributes(&ObjAttr, &UnicodeString, 0, NULL, NULL); + + Status = NtCreateFile(&hKeyboard, + FILE_READ_DATA | SYNCHRONIZE, + &ObjAttr, + &IoStatus, + NULL, 0, 0, FILE_OPEN_IF, 0, NULL, 0 + ); + + if (!NT_SUCCESS(Status)) { + hKeyboard = 0; + goto GiveUp; + } + else { + KeyboardEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!KeyboardEvent) { + goto GiveUp; + } + } + + kuid.UnitId = 0; + Status = NtDeviceIoControlFile(hKeyboard, + KeyboardEvent, + NULL, NULL, // apcrtn, apccontext + &IoStatus, + IOCTL_KEYBOARD_QUERY_INDICATORS, + &kuid, sizeof(kuid), + &kip, sizeof(kip) + ); + + if (!NT_SUCCESS(Status)) { + goto GiveUp; + } + + + Status = NtWaitForSingleObject(KeyboardEvent, FALSE, NULL); + if (Status != STATUS_SUCCESS) { + goto GiveUp; + } + + + ControlKeyState = 0; + if (kip.LedFlags & KEYBOARD_CAPS_LOCK_ON) { + ControlKeyState |= CAPSLOCK_ON; + } + + if (kip.LedFlags & KEYBOARD_NUM_LOCK_ON) { + ControlKeyState |= NUMLOCK_ON; + } + + if (kip.LedFlags & KEYBOARD_SCROLL_LOCK_ON) { + ControlKeyState |= SCROLLLOCK_ON; + } + +GiveUp: + + if (hKeyboard) { + NtClose(hKeyboard); + } + + if (KeyboardEvent) { + NtClose(KeyboardEvent); + } + + + ToggleKeyState = ControlKeyState; + KbdLed = 0; + if (ToggleKeyState & NUMLOCK_ON) { + KbdLed |= NUM_STATE; + } + if (ToggleKeyState & CAPSLOCK_ON) { + KbdLed |= CAPS_STATE; + } + if (ToggleKeyState & SCROLLLOCK_ON) { + KbdLed |= SCROLL_STATE; + } + + sas_store (kb_flag,KbdLed); + sas_store (kb_flag_2,(unsigned char)(KbdLed >> 4)); + + return; +} + + + +#define NUMBBIRECS 32 +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::: Return keys in BIOS buffer ::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +VOID ReturnBiosBufferKeys(VOID) +{ + int i; + DWORD dwRecs; + word BufferHead; + word BufferTail; + word BufferEnd; + word BufferStart; + word w; + USHORT usKeyState; + UCHAR AsciiChar, Digit; + WCHAR UnicodeChar; + + INPUT_RECORD InputRecord[NUMBBIRECS]; + + sas_loadw(BIOS_KB_BUFFER_HEAD, &BufferHead); + sas_loadw(BIOS_KB_BUFFER_TAIL, &BufferTail); + sas_loadw(BIOS_KB_BUFFER_END, &BufferEnd); + sas_loadw(BIOS_KB_BUFFER_START,&BufferStart); + + i = NUMBBIRECS - 1; + while (BufferHead != BufferTail) { + + /* + * Get Scode\char from bios buffer, starting from + * the last key entered. + */ + BufferTail -= 2; + if (BufferTail < BufferStart) { + BufferTail = BufferEnd-2; + } + sas_loadw(BIOS_VAR_START + BufferTail, &w); + + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.wVirtualScanCode = w >> 8; + AsciiChar = (UCHAR)w & 0xFF; + (UCHAR)InputRecord[i].Event.KeyEvent.uChar.AsciiChar = AsciiChar; + + /* + * Translate the character stuff in InputRecord. + * we start filling InputRecord from the bottom + * we are working from the last key entered, towards + * the oldest key. + */ + if (!BiosKeyToInputRecord(&InputRecord[i].Event.KeyEvent)) { + ; // error in translation skip it + } + + // normal case + else if (InputRecord[i].Event.KeyEvent.wVirtualScanCode) { + InputRecord[i].Event.KeyEvent.bKeyDown = FALSE; + InputRecord[i-1] = InputRecord[i]; + i--; + InputRecord[i--].Event.KeyEvent.bKeyDown = TRUE; + } + + // Special character codes with no scan code are + // generated by simulating the alt-num pad entry + else if (InputRecord[i].Event.KeyEvent.uChar.AsciiChar) + { + UnicodeChar = InputRecord[i].Event.KeyEvent.uChar.UnicodeChar; + + // write out what we have, ensuring we have space + if (i != NUMBBIRECS - 1) { + WriteConsoleInputVDMW(sc.InputHandle, + &InputRecord[i+1], + NUMBBIRECS - i - 1, + &dwRecs); + i = NUMBBIRECS - 1; + } + + + + // restore NUMLOCK state if needed + usKeyState = (USHORT)GetKeyState(VK_NUMLOCK); + if (!(usKeyState & 1)) { + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.wVirtualScanCode = 0x45; + InputRecord[i].Event.KeyEvent.uChar.UnicodeChar = 0; + InputRecord[i].Event.KeyEvent.wVirtualKeyCode = VK_NUMLOCK; + InputRecord[i].Event.KeyEvent.dwControlKeyState = NUMLOCK_ON; + InputRecord[i].Event.KeyEvent.wRepeatCount = 1; + InputRecord[i--].Event.KeyEvent.bKeyDown = FALSE; + InputRecord[i] = InputRecord[0]; + InputRecord[i--].Event.KeyEvent.bKeyDown = TRUE; + } + + // alt up + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.wVirtualScanCode = 0x38; + InputRecord[i].Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; + InputRecord[i].Event.KeyEvent.wVirtualKeyCode = VK_MENU; + InputRecord[i].Event.KeyEvent.dwControlKeyState = NUMLOCK_ON; + InputRecord[i].Event.KeyEvent.wRepeatCount = 1; + InputRecord[i--].Event.KeyEvent.bKeyDown = FALSE; + + // up/down for each digits, starting with lsdigit + while (AsciiChar) { + Digit = AsciiChar % 10; + AsciiChar /= 10; + + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.uChar.UnicodeChar = 0; + InputRecord[i].Event.KeyEvent.wVirtualScanCode= aNumPadSCode[Digit]; + InputRecord[i].Event.KeyEvent.wVirtualKeyCode = VK_NUMPAD0+Digit; + InputRecord[i].Event.KeyEvent.dwControlKeyState = NUMLOCK_ON | LEFT_ALT_PRESSED; + InputRecord[i].Event.KeyEvent.bKeyDown = FALSE; + InputRecord[i-1] = InputRecord[i]; + i--; + InputRecord[i--].Event.KeyEvent.bKeyDown = TRUE; + } + + // send alt down + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.wVirtualScanCode = 0x38; + InputRecord[i].Event.KeyEvent.uChar.UnicodeChar = 0; + InputRecord[i].Event.KeyEvent.wVirtualKeyCode = VK_MENU; + InputRecord[i].Event.KeyEvent.dwControlKeyState = NUMLOCK_ON | LEFT_ALT_PRESSED; + InputRecord[i].Event.KeyEvent.wRepeatCount = 1; + InputRecord[i--].Event.KeyEvent.bKeyDown = TRUE; + + + // toggel numpad state if needed + if (!(usKeyState & 1)) { + InputRecord[i].EventType = KEY_EVENT; + InputRecord[i].Event.KeyEvent.wVirtualScanCode = 0x45; + InputRecord[i].Event.KeyEvent.uChar.UnicodeChar = 0; + InputRecord[i].Event.KeyEvent.wVirtualKeyCode = VK_NUMLOCK; + InputRecord[i].Event.KeyEvent.dwControlKeyState = NUMLOCK_ON; + InputRecord[i].Event.KeyEvent.wRepeatCount = 1; + InputRecord[i].Event.KeyEvent.bKeyDown = FALSE; + InputRecord[i-1] = InputRecord[i]; + i--; + InputRecord[i--].Event.KeyEvent.bKeyDown = TRUE; + } + } + + + + + /* If buffer is full or + * bios buffer is empty and got stuff in buffer + * Write it out + */ + if ((BufferHead == BufferTail && i != NUMBBIRECS - 1) || i < 0) + { + WriteConsoleInputVDMW(sc.InputHandle, + &InputRecord[i+1], + NUMBBIRECS - i - 1, + &dwRecs); + i = NUMBBIRECS - 1; + } + } + + + sas_storew(BIOS_KB_BUFFER_TAIL, BufferTail); + + return; +} + + + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Return key to the console input buffer ::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void ReturnUnusedKeyEvents(int UnusedKeyEvents) +{ + INPUT_RECORD InputRecords[MAX_KEY_EVENTS]; + DWORD RecsWrt; + int KeyToRtn, KeyInx; + + /* Return keys to console input buffer */ + + if(UnusedKeyEvents) + { + for(KeyToRtn = 1, KeyInx = UnusedKeyEvents-1; + KeyToRtn <= UnusedKeyEvents && + GetHistoryKeyEvent(&InputRecords[KeyInx].Event.KeyEvent,KeyToRtn); + KeyToRtn++,KeyInx--) + { + InputRecords[KeyToRtn - 1].EventType = KEY_EVENT; + } + + if(!WriteConsoleInputVDMW(sc.InputHandle,InputRecords,KeyToRtn,&RecsWrt)) + always_trace0("Console write failed\n"); + } + + /* Clear down key history buffer and event queue */ + InitKeyHistory(); + InitQueue(); +} + + +/* + * Attempts to terminate this console group + */ +void cmdPushExitInConsoleBuffer (void) +{ + if (VDMForWOW) { + return; + } + CntrlHandlerState |= CNTRL_PUSHEXIT; + + /* + * Signal all processes in this group that they should be + * terminating. Do this by posting a WM_CLOSE message to + * the console window, which causes console to send control + * close event to all processes. + * + * The vdm must be able to receive control events from the + * console after posting the WM_CLOSE msg since the vdm's + * CntrlHandler is still registered. To be safe we do + * vdm specific cleanup first, and let the CntrlHandler + * do the ExitProcess(). This avoids possible deadlock\race + * conditions with the console. + */ + host_applClose(); + ExitVDM(FALSE,0); + PostMessage(hWndConsole, WM_CLOSE, 0,0); + ExitThread(0); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Calculate no. of keys to return to console input buffer :::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +extern int keys_in_6805_buff(int *part_key_transferred); + +int CalcNumberOfUnusedKeyEvents() +{ + int part_key_transferred; + + //Get the number of keys in the 6805 buffer + return (keys_in_6805_buff(&part_key_transferred) + KeyQueue.KeyCount); +} diff --git a/private/mvdm/softpc.new/host/src/nt_fdisk.c b/private/mvdm/softpc.new/host/src/nt_fdisk.c new file mode 100644 index 000000000..915b26f03 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_fdisk.c @@ -0,0 +1,760 @@ + + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntdddisk.h> +#include <windows.h> +#include "insignia.h" +#include "host_def.h" + +/* + * [ Product: SoftPC-AT Revision 3.0 + * + * Name: nt_fdisk.c + * + * Derived From: unix_fdisk.c (Andrew Guthrie/Ade Brownlow) + * + * Authors: Jerry Sexton + * + * Created On: 7th August 1991 + * + * Purpose: This module handles the host side of opening, closing, + * verfiying and locking hard disks. + * + * (c)Copyright Insignia Solutions Ltd., 1991. All rights reserved. + * + * ] */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys\types.h> +#include "xt.h" +#include "config.h" +#include "trace.h" +#include "error.h" +#include "nt_uis.h" +#include "nt_reset.h" +#include "nt_fdisk.h" + +/********************************************************/ +/* + * Maximum disk size is 32 Megabytes for DOS. Our disk geometry is based upon + * a variable number of cylinders (as per user request when creating a virgin + * hard disk) with bytes per sector, sectors per track and heads per drive + * fixed as per above. Since a real disk always contains an integral number + * of cylinders and since we allow the user to specify disk size at a + * granularity of 1 Megabyte, this means we allocate disk space in terms of + * an integral number of 30 cylinders (30,60, ...). (30 cylinders is + * approximately 1 Megabyte). One disk allocation unit = 30 cylinders. The + * max.number of allocation units is 32. For the AT, it is possible to have + * larger disks (e.g up to 1024 cylinders and 16 heads). For compatability + * with SoftPC Rev.1, we still use Rev.1 limitations on disk geometry + */ +#define ONEMEG 1024 * 1024 +#define HD_MAX_DISKALLOCUN 32 +#define HD_SECTORS_PER_TRACK 17 +#define HD_HEADS_PER_DRIVE 4 +#define HD_BYTES_PER_SECTOR 512 +#define HD_SECTORS_PER_CYL (HD_HEADS_PER_DRIVE * HD_SECTORS_PER_TRACK) +#define HD_BYTES_PER_CYL (HD_BYTES_PER_SECTOR * HD_SECTORS_PER_CYL) +#define HD_DISKALLOCUNSIZE (HD_BYTES_PER_CYL * 30) +#define MIN_PARSIZE (HD_SECTORS_PER_TRACK * HD_HEADS_PER_DRIVE * 30) +#define MAX_PARSIZE (MIN_PARSIZE * HD_MAX_DISKALLOCUN) +#define SECTORS 0x0c /* offset in buffer for sectors in partition + * marker */ +#define MAX_PARTITIONS 5 +#define START_PARTITION 0x1be +#define SIZE_PARTITION 16 +#define SIGNATURE_LEN 2 + + +/* + * drive information ... indication of whether file is open; the file + * descriptor, and the current file pointer value + */ +typedef struct +{ + int fd; + int valid_fd; + int curoffset; + SHORT n_cyl; + SHORT valid_n_cyl; + UTINY n_heads; + UTINY valid_n_heads; + int n_sect; + int valid_n_sect; + BOOL open; + BOOL valid_open; + BOOL readonly; + BOOL valid_readonly; +} DrvInfo; + +LOCAL DrvInfo fdiskAdapt[2]; + +// fail nicely if this is set - should only need to be used for initialisation +// support. Set in config dependant on CONT_FILE environment var +// +LOCAL BOOL DiskValid = FALSE; + +GLOBAL VOID host_using_fdisk(BOOL status) +{ + DiskValid = status; +} + +GLOBAL SHORT +host_fdisk_valid + (UTINY hostID, ConfigValues *vals, NameTable *table, CHAR *errStr) +{ + DrvInfo *adaptP; + + adaptP = fdiskAdapt + (hostID - C_HARD_DISK1_NAME); + + adaptP->n_cyl = (SHORT) 30; + adaptP->n_heads = 4; + adaptP->n_sect = 17; + return C_CONFIG_OP_OK; + +} + +GLOBAL VOID +host_fdisk_change(UTINY hostID, BOOL apply) +{ + return; // don't bother if no disk. +} + +GLOBAL SHORT +host_fdisk_active(UTINY hostID, BOOL active, CHAR *errString) +{ + return C_CONFIG_OP_OK; // just say it's there... +} + +GLOBAL VOID +host_fdisk_term(VOID) +{ + host_fdisk_change(C_HARD_DISK1_NAME, FALSE); + host_fdisk_change(C_HARD_DISK2_NAME, FALSE); +} + +GLOBAL VOID +host_fdisk_get_params(int driveid, int *n_cyl, int *n_heads, int *n_sect) +{ + DrvInfo *adaptP = &fdiskAdapt[driveid]; + + *n_cyl = adaptP->n_cyl; + *n_heads = adaptP->n_heads; + *n_sect = adaptP->n_sect; +} + +GLOBAL VOID +host_fdisk_seek0(driveid) +int driveid; +{ + + return; // don't bother if no disk. +} + +/********************************************************/ +/* + * Read and write routines (called from diskbios.c & fdisk.c + */ +int +host_fdisk_rd(int driveid, int offset, int nsecs, char *buf) +{ + return(0); // no disk...no data +} + +int +host_fdisk_wt(int driveid, int offset, int nsecs, char *buf) +{ + return(0); // no disk...no data +} + +// FDISK support + + +#pragma pack(1) + +#define MAX_FDISK_NAME 9 +typedef struct _FDISKDATA { + BYTE drive; + BYTE idle_counter; + CHAR drive_letter; + BOOLEAN auto_locked; + HANDLE fdisk_fd; + DWORD num_heads; + LARGE_INTEGER num_cylinders; + DWORD sectors_per_track; + DWORD bytes_per_sector; + DWORD align_factor; + USHORT owner_pdb; + CHAR device_name[MAX_FDISK_NAME]; +} FDISKDATA, *PFDISKDATA; + + +// Bios Parameter Block (BPB) +// copied from DEMDASD.H +typedef struct A_BPB { +WORD SectorSize; // sector size in bytes +BYTE ClusterSize; // cluster size in sectors +WORD ReservedSectors; // number of reserved sectors +BYTE FATs; // number of FATs +WORD RootDirs; // number of root directory entries +WORD Sectors; // number of sectors +BYTE MediaID; // media descriptor +WORD FATSize; // FAT size in sectors +WORD TrackSize; // track size in sectors; +WORD Heads; // number of heads +DWORD HiddenSectors; // number of hidden sectors +DWORD BigSectors; // number of sectors for big media +} BPB, *PBPB; + +typedef struct _BOOTSECTOR { + BYTE Jump; + BYTE Target[2]; + BYTE OemName[8]; + BPB bpb; +} BOOTSECTOR, * PBOOTSECTOR; + +#pragma pack() + + + +// this is the cylinder size of a 2.88 diskette +#define MAX_DISKIO_SIZE 0x9000 +#define FDISK_IDLE_PERIOD 30 +PFDISKDATA fdisk_data_table = NULL; +BYTE number_of_fdisk = 0; +DWORD max_align_factor = 0; +DWORD disk_buffer_pool = 0; +DWORD cur_align_factor; +WORD fdisk_open_count = 0; + +WORD * pFDAccess = 0; + +extern USHORT * pusCurrentPDB; + +extern int DiskOpenRetry(CHAR); + + +BOOL nt_fdisk_init( + BYTE drive, + PBPB bpb, + PDISK_GEOMETRY disk_geometry +); + + + +BOOL nt_fdisk_close(BYTE drive); + +PFDISKDATA get_fdisk_data( + BYTE drive +); + +BOOL get_fdisk_handle( + PFDISKDATA fdisk_data, + USHORT pdb, + BOOL auto_lock +); + + +VOID FdiskTerminatePDB(USHORT PDB); +VOID HostFdiskReset(VOID); + +BOOL close_fdisk( + PFDISKDATA fdisk_data +); + + +BOOL nt_fdisk_init(BYTE drive, PBPB bpb, PDISK_GEOMETRY disk_geometry) +{ + PFDISKDATA fdisk_data; + PUNICODE_STRING unicode_string; + ANSI_STRING ansi_string; + NTSTATUS status; + OBJECT_ATTRIBUTES fdisk_obj; + IO_STATUS_BLOCK io_status_block; + FSCTL_QUERY_FAT_BPB_BUFFER boot_sector_first_0x24_bytes; + HANDLE fd; + FILE_ALIGNMENT_INFORMATION align_info; + CHAR dos_device_name[] = "\\\\.\\?:"; + CHAR nt_device_name[] = "\\DosDevices\\?:"; + + nt_device_name[12] = + dos_device_name[4] = drive + 'A'; + RtlInitAnsiString( &ansi_string, nt_device_name); + + unicode_string = &NtCurrentTeb()->StaticUnicodeString; + + status = RtlAnsiStringToUnicodeString(unicode_string, + &ansi_string, + FALSE + ); + if ( !NT_SUCCESS(status) ) + return FALSE; + + + InitializeObjectAttributes( + &fdisk_obj, + unicode_string, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + status = NtOpenFile( + &fd, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &fdisk_obj, + &io_status_block, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + + if (!NT_SUCCESS(status)) + return FALSE; + + // get geomerty information, the caller wants this + status = NtDeviceIoControlFile(fd, + 0, + NULL, + NULL, + &io_status_block, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + disk_geometry, + sizeof (DISK_GEOMETRY) + ); + if (!NT_SUCCESS(status)) { + NtClose(fd); + return FALSE; + } + // get alignment factor + status = NtQueryInformationFile(fd, + &io_status_block, + &align_info, + sizeof(FILE_ALIGNMENT_INFORMATION), + FileAlignmentInformation + ); + + if (!NT_SUCCESS(status)) { + NtClose(fd); + return(FALSE); + } + if (align_info.AlignmentRequirement > max_align_factor) + max_align_factor = align_info.AlignmentRequirement; + + + /* get BPB, it will fail if the drive is not a FAT partition */ + status = NtFsControlFile(fd, + 0, + NULL, + NULL, + &io_status_block, + FSCTL_QUERY_FAT_BPB, + NULL, + 0, + &boot_sector_first_0x24_bytes, + sizeof(boot_sector_first_0x24_bytes) + ); + if (!NT_SUCCESS(status)) { + NtClose(fd); + return (FALSE); + } + + *bpb = ((PBOOTSECTOR)&boot_sector_first_0x24_bytes)->bpb; + + + // enlarge the table + fdisk_data = (PFDISKDATA) realloc(fdisk_data_table, + (number_of_fdisk + 1) * sizeof(FDISKDATA) + ); + if(fdisk_data == NULL) { + NtClose(fd); + return FALSE; + } + fdisk_data_table = fdisk_data; + fdisk_data += number_of_fdisk; + fdisk_data->drive_letter = drive + 'A'; + fdisk_data->drive = number_of_fdisk; + fdisk_data->fdisk_fd = INVALID_HANDLE_VALUE; + fdisk_data->num_heads = disk_geometry->TracksPerCylinder; + fdisk_data->sectors_per_track = disk_geometry->SectorsPerTrack; + fdisk_data->bytes_per_sector = disk_geometry->BytesPerSector; + fdisk_data->num_cylinders = disk_geometry->Cylinders; + fdisk_data->align_factor = align_info.AlignmentRequirement; + strcpy(fdisk_data->device_name, dos_device_name); + number_of_fdisk++; + NtClose(fd); + return TRUE; +} + + +ULONG nt_fdisk_read( + BYTE drive, + PLARGE_INTEGER offset, + ULONG size, + PBYTE buffer +) +{ + PFDISKDATA fdisk_data; + ULONG size_returned = 0; + + if ((fdisk_data = get_fdisk_data(drive)) == NULL) + return 0; + if (get_fdisk_handle(fdisk_data, *pusCurrentPDB, FALSE)) + return(disk_read(fdisk_data->fdisk_fd, + offset, + size, + buffer)); +} + + +ULONG nt_fdisk_write( + BYTE drive, + PLARGE_INTEGER offset, + ULONG size, + PBYTE buffer +) +{ + PFDISKDATA fdisk_data; + ULONG size_returned = 0; + + if ((fdisk_data = get_fdisk_data(drive)) == NULL) + return 0; + + if (get_fdisk_handle(fdisk_data, *pusCurrentPDB, TRUE)) { + // must lock the drive. This is very important. + size_returned = disk_write(fdisk_data->fdisk_fd, + offset, + size, + buffer); + } + return size_returned; +} + + +BOOL nt_fdisk_verify( + BYTE drive, + PLARGE_INTEGER offset, + ULONG size +) +{ + + PFDISKDATA fdisk_data; + ULONG size_returned = 0; + VERIFY_INFORMATION verify_info; + + if ((fdisk_data = get_fdisk_data(drive)) == NULL) + return FALSE; + + if (get_fdisk_handle(fdisk_data, *pusCurrentPDB, FALSE)) { + verify_info.StartingOffset = *offset; + verify_info.Length = size; + return(DeviceIoControl(fdisk_data->fdisk_fd, + IOCTL_DISK_VERIFY, + &verify_info, + sizeof(VERIFY_INFORMATION), + NULL, + 0, + &size_returned, + NULL + )); + } + +} + + + +BOOL nt_fdisk_close(BYTE drive) +{ + PFDISKDATA fdisk_data; + if ((fdisk_data = get_fdisk_data(drive)) == NULL) + return FALSE; + return(close_fdisk(fdisk_data)); +} + + +BOOL close_fdisk(PFDISKDATA fdisk_data) +{ + + if (fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE){ + CloseHandle(fdisk_data->fdisk_fd); + fdisk_data->auto_locked = FALSE; + fdisk_data->fdisk_fd = INVALID_HANDLE_VALUE; + fdisk_data->owner_pdb = 0; + (*(pFDAccess))--; + fdisk_open_count--; + } + return TRUE; +} + + + +PFDISKDATA get_fdisk_data(BYTE drive) +{ + + WORD i; + + for (i = 0; i < number_of_fdisk; i++) + if (fdisk_data_table[i].drive == drive) + return &fdisk_data_table[i]; + return NULL; +} + + +BOOL get_fdisk_handle(PFDISKDATA fdisk_data, USHORT pdb, BOOL auto_lock) +{ + + DWORD share_access; + DWORD last_error; + + + + if (fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE && + ((auto_lock && !fdisk_data->auto_locked) || fdisk_data->owner_pdb != pdb)) + + close_fdisk(fdisk_data); + + share_access = (auto_lock) ? FILE_SHARE_READ : + FILE_SHARE_READ | FILE_SHARE_WRITE; + + while (fdisk_data->fdisk_fd == INVALID_HANDLE_VALUE) { + + fdisk_data->fdisk_fd = CreateFile (fdisk_data->device_name, + SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, + share_access, + NULL, + OPEN_EXISTING, + 0, + 0 + ); + if (fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE) { + fdisk_data->auto_locked = auto_lock; + fdisk_data->owner_pdb = pdb; + fdisk_open_count++; + (*(pFDAccess))++; + break; + } + else { + last_error = GetLastError(); + + if (last_error == ERROR_SHARING_VIOLATION && + DiskOpenRetry(fdisk_data->drive_letter) == RMB_RETRY) + continue; + else if (last_error == ERROR_ACCESS_DENIED) { + /* the user doesn't have enough privilege to + * directly access the drive, display the pop up + * "terminate" ->terminate ntvdm process + * "ignore" -> fail the call and let application + * handles the error. + */ + + host_direct_access_error((ULONG)NOSUPPORT_HARDDISK); + break; + } + else + /* simply fail the call for other error conditions */ + break; + + } + + } + + if(fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE) { + // have the current align factor updated + cur_align_factor = fdisk_data->align_factor; + } + fdisk_data->idle_counter = FDISK_IDLE_PERIOD; + + return(!(fdisk_data->fdisk_fd == INVALID_HANDLE_VALUE)); +} + +void fdisk_heart_beat(void) +{ + WORD i; + PFDISKDATA fdisk_data; + if (fdisk_open_count != 0) { + for (i = 0; i < number_of_fdisk; i++) { + fdisk_data = &fdisk_data_table[i]; + if(fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE && + --fdisk_data->idle_counter == 0){ + close_fdisk(fdisk_data); + } + } + } +} + + +VOID HostFdiskReset(VOID) +{ + FdiskTerminatePDB((USHORT)0); +} + +VOID FdiskTerminatePDB(USHORT PDB) +{ + WORD i; + PFDISKDATA fdisk_data; + + if (fdisk_open_count != 0) { + for(i = 0; i < number_of_fdisk; i++) { + fdisk_data = &fdisk_data_table[i]; + if (fdisk_data->fdisk_fd != INVALID_HANDLE_VALUE && + (PDB == 0 || fdisk_data->owner_pdb == PDB)) { + close_fdisk(fdisk_data); + } + } + } + + +} +// Generic disk read. +// this function takes care of buffer alignment requirement(cur_align_factor) +// and split the calls to file system if the given size is larger than +// MAX_DISKIO_SIZE -- File system may fail the request if the size +// is too big. We create a buffer worhty for 36KB(cylinder size of a +// 2.88 floppy) the first time application touch disks. + +ULONG disk_read( + HANDLE fd, + PLARGE_INTEGER offset, + DWORD size, + PBYTE buffer +) +{ + PBYTE read_buffer; + DWORD block_size; + DWORD size_returned; + DWORD read_size; + + if (fd == INVALID_HANDLE_VALUE || + (SetFilePointer(fd, offset->LowPart, &offset->HighPart, + FILE_BEGIN) == 0xFFFFFFFF)) + { + return 0; + } + block_size = (size <= MAX_DISKIO_SIZE) ? size : MAX_DISKIO_SIZE; + + // if the given buffer is not aligned, use our buffer and do a + // double copy + if (cur_align_factor != 0) { + read_buffer = get_aligned_disk_buffer(); + if (read_buffer == NULL) + return 0; + } + else { + read_buffer = buffer; + } + read_size = 0; + while (size != 0) { + if (size < block_size) + block_size = size; + if (!ReadFile(fd, (PVOID)read_buffer, block_size, &size_returned, 0) + || size_returned != block_size) + break; + if(cur_align_factor != 0) { + // read operation, read and then copy + memcpy(buffer, (PVOID)read_buffer, block_size); + buffer += block_size; + } + else + read_buffer += block_size; + size -= block_size; + read_size += block_size; + } + return read_size; +} + +ULONG disk_write( + HANDLE fd, + PLARGE_INTEGER offset, + DWORD size, + PBYTE buffer +) +{ + PBYTE write_buffer; + DWORD block_size; + DWORD size_returned; + DWORD written_size; + + if (fd == INVALID_HANDLE_VALUE || + (SetFilePointer(fd, offset->LowPart, &offset->HighPart, + FILE_BEGIN) == 0xFFFFFFFF)) + { + return 0; + } + block_size = (size <= MAX_DISKIO_SIZE) ? size : MAX_DISKIO_SIZE; + + // if the given buffer is not aligned, use our buffer and do a + // double copy + if (cur_align_factor != 0 && + (write_buffer = get_aligned_disk_buffer()) == NULL) + return 0; + written_size = 0; + while (size != 0) { + if (size < block_size) + block_size = size; + if(cur_align_factor != 0) + // write operation, copy and then write + memcpy((PVOID)write_buffer, buffer, block_size); + else + write_buffer = buffer; + + if (!WriteFile(fd, (PVOID)write_buffer, block_size, &size_returned, 0) + || size_returned != block_size) + break; + size -= block_size; + buffer += block_size; + written_size += block_size; + } + return written_size; +} + +// Hard disk verify actually goes to file system directly because +// the IOCTL_DISK_VERIFY will do the work. This ioctl doesn't work for +// floppy. This function is mainly provided for floppy verify. +BOOL disk_verify( + HANDLE fd, + PLARGE_INTEGER offset, + DWORD size +) +{ + PBYTE verify_buffer; + DWORD block_size; + DWORD size_returned; + + if (fd == INVALID_HANDLE_VALUE || + (SetFilePointer(fd, offset->LowPart, &offset->HighPart, + FILE_BEGIN) == 0xFFFFFFFF)) + { + return FALSE; + } + block_size = (size <= MAX_DISKIO_SIZE) ? size : MAX_DISKIO_SIZE; + // if this is the first time application do a real work, + // allocate the buffer + if ((verify_buffer = get_aligned_disk_buffer()) == NULL) + return FALSE; + while (size != 0) { + if (size < block_size) + block_size = size; + if (!ReadFile(fd, (PVOID)verify_buffer, block_size, &size_returned, 0) + || size_returned != block_size) + { + return FALSE; + } + size -= block_size; + } + return TRUE; +} + +PBYTE get_aligned_disk_buffer(void) +{ + // if we don't have the buffer yet, get it + if (disk_buffer_pool == 0) { + disk_buffer_pool = (DWORD) malloc(MAX_DISKIO_SIZE + max_align_factor); + if (disk_buffer_pool == 0) + return NULL; + } + return((PBYTE)((disk_buffer_pool + cur_align_factor) & ~(cur_align_factor))); + +} diff --git a/private/mvdm/softpc.new/host/src/nt_fulsc.c b/private/mvdm/softpc.new/host/src/nt_fulsc.c new file mode 100644 index 000000000..1fbe4ced0 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_fulsc.c @@ -0,0 +1,2415 @@ +#include <windows.h> +#include "host_def.h" +#include "insignia.h" + +/* + * ========================================================================== + * Name: nt_fulsc.c + * Author: Jerry Sexton + * Derived From: + * Created On: 27th January 1992 + * Purpose: This module contains the code required to handle + * transitions between graphics and text modes, and + * windowed and full-screen displays for SoftPC running + * under the x86 monitor. + * + * (c)Copyright Insignia Solutions Ltd., 1992. All rights reserved. + * ========================================================================== + */ + +/* + * ========================================================================== + * Other Includes + * ========================================================================== + */ +#ifdef X86GFX +#include <ntddvdeo.h> +#endif +#include <vdm.h> +#include <stdlib.h> +#include <string.h> +#include "conapi.h" + +#include "xt.h" +#include CpuH +#include "gvi.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "video.h" +#include "egacpu.h" +#include "egavideo.h" +#include "egagraph.h" +#include "egaports.h" +#include "egamode.h" +#include "ckmalloc.h" +#include "sas.h" +#include "ica.h" +#include "ios.h" +#include "config.h" +#include "idetect.h" +#include "debug.h" + +#include "nt_thred.h" +#include "nt_fulsc.h" +#include "nt_graph.h" +#include "nt_uis.h" +#include "host_rrr.h" +#include "nt_det.h" +#include "nt_mouse.h" +#include "nt_event.h" +#include "ntcheese.h" +#include "nt_eoi.h" +#include "nt_reset.h" + +/* + * ========================================================================== + * Global Data + * ========================================================================== + */ +GLOBAL BOOL ConsoleInitialised = FALSE; +GLOBAL BOOL ConsoleNoUpdates = FALSE; +#ifdef X86GFX +GLOBAL BOOL BiosModeChange = FALSE; +GLOBAL DWORD mouse_buffer_width = 0, + mouse_buffer_height = 0; +#endif /* X86GFX */ +GLOBAL BOOL blocked_in_gfx_mode = FALSE; /* need to force text mode? */ +#ifndef PROD +GLOBAL UTINY FullScreenDebug = FALSE; +#endif /* PROD */ + +/* We have to prevent bad values from oddball video cards (eg Prodesigner II + * EISA) from blatting us before we can load our private baby mode table in + * ntio.sys. We have to keep another copy to be copied into memory to prevent + * this. We should only need modes 3 & b. + */ +GLOBAL UTINY tempbabymode[] = +/* 80x25 stuff */ + { + 0x50, 0x18, 0x10, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x67, + 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, + 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, + 0x1f, 0x96, 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x0e, 0x00, 0xff, +/* mode b stuff */ + 0x5e, 0x32, 0x08, 0x00, 0x97, 0x01, 0x0f, 0x00, 0x06, 0xe7, + 0x6d, 0x5d, 0x5e, 0x90, 0x61, 0x8f, 0xbf, 0x1f, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x8e, 0x99, 0x2f, + 0x00, 0xa1, 0xb9, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x0f, 0xff +}; + +/* + * ========================================================================== + * Local Data + * ========================================================================== + */ + +/* The resolution and font-size at start-up. */ +LOCAL COORD startUpResolution; +LOCAL COORD startUpFontSize; + +/* General purpose console buffer. */ +LOCAL CHAR_INFO consoleBuffer[MAX_CONSOLE_SIZE]; + +LOCAL BOOL WinFrozen = FALSE; + +/* Console info from startup which is needed for synchronisation */ +LOCAL int ConVGAHeight; +LOCAL int ConTopLine; + +/* saved information for console re-integration */ +LOCAL CONSOLE_SCREEN_BUFFER_INFO ConsBufferInfo; +LOCAL StartupCharHeight; + +LOCAL half_word saved_text_lines; /* No of lines for last SelectMouseBuffer. */ + + +/* Variable to check for changes in screen state. */ +GLOBAL DWORD savedScreenState; +BOOL nt_init_called = 0; + +IMPORT CONSOLE_CURSOR_INFO StartupCursor; + +IMPORT void low_set_mode(int); +IMPORT VOID recalc_text(int); +IMPORT VOID enable_gfx_update_routines(VOID); +IMPORT VOID disable_gfx_update_routines(VOID); +#ifdef X86GFX +IMPORT void vga_misc_inb(io_addr, half_word *); +#endif /* X86GFX */ + + +/* + * ========================================================================== + * Local Function Declarations + * ========================================================================== + */ +VOID enableUpdates(VOID); +VOID disableUpdates(VOID); +VOID copyConsoleToRegen(SHORT, SHORT, SHORT, SHORT); +VOID getVDMCursorPosition(VOID); +VOID setVDMCursorPosition(UTINY, PCOORD); +VOID waitForInputFocus(VOID); +GLOBAL int getModeType(VOID); +#ifdef X86GFX +VOID AddTempIVTFixups(VOID); +VOID GfxReset(VOID); +#endif /* X86GFX */ + +/* + * ========================================================================== + * Global Functions + * ========================================================================== + */ + +GLOBAL VOID nt_init_event_thread(VOID) +{ + note_entrance0("nt_init_event_thread"); + + /* + * May be called more than once, if event thread enters + * resume\block code before normally intialized + */ + if (nt_init_called) + return; + else + nt_init_called++; + + + if (sc.ScreenState != STREAM_IO) { + /* + ** Copy the console buffer to the regen buffer. + ** Don't want to adjust the copy from top of console window, console + ** does it itself if we resize the window. Tim September 92. + */ + copyConsoleToRegen(0, 0, VGA_WIDTH, (SHORT)ConVGAHeight); + + /* + ** Tim September 92, adjust cursor position if console window size is + ** adjusted. + */ + ConsBufferInfo.dwCursorPosition.Y -= ConTopLine; + + /* Set up SoftPC's cursor. */ + setVDMCursorPosition((UTINY)StartupCharHeight, + &ConsBufferInfo.dwCursorPosition); + + if (sc.ScreenState == WINDOWED) + enableUpdates(); + } + else + enableUpdates(); + + // set kbd state flags in biosdata area, according to the real kbd Leds + if (!VDMForWOW) { + SyncBiosKbdLedToKbdDevice(); + // we have sync up the BIOS led states with the system, we now let the + // event thread go + ResumeThread(ThreadInfo.EventMgr.Handle); + } + + KbdResume(); // JonLe Mod +} + + +#ifdef X86GFX +/* +* Find the address of the ROM font, load it up into the correct +* portion of the regen area and set Int 43 to point to it. +* +* Size of font we are loading is known, so don't listen to what +* the native BIOS returns to us in CX. BIOS might be returning +* character height we set in recalc_text() above. Tim Oct 92. +*/ + +NativeFontAddr nativeFontAddresses[6]; /* pointers to native BIOS ROM fonts */ + /* 8x14, 8x8 pt1, 8x8 pt2, 9x14, 8x16 and 9x16 */ + + +#define GET_BIOS_FONT_ADDRESS(FontIndex) \ + (((sys_addr)nativeFontAddresses[FontIndex].seg << 4) + \ + (sys_addr)nativeFontAddresses[FontIndex].off) + +/* +***************************************************************************** +** locateNativeBIOSfonts() X86 only. +***************************************************************************** +** Get the addresses of the BIOS ROM fonts. (Insignia video ROM not loaded) +** ntdetect.com runs the INT 10 to look the addresses up on system boot and +** stores them in page 0 at 700. +** This function is called once on startup X86 only. It gets the addresses of +** the native ROM fonts and stores them in the nativeFontAddresses[] array. +*/ +VOID locateNativeBIOSfonts IFN0() +{ + int i; + sys_addr font_off = 0x700; /* Magic place used by ntdetect.com */ + + for(i = 0; i < 6; i++) + { + sas_loadw(font_off, &nativeFontAddresses[i].off); + sas_loadw(font_off+2, &nativeFontAddresses[i].seg); + font_off += 4; + } +} /* end of locateNativeBIOSfonts() */ + +/* +**************************************************************************** +** loadNativeBIOSfont() X86 only. +**************************************************************************** +** Loads the appropriate font, specified by current window size, into the +** font area in video RAM. +** This function is called on every windowed startup and resume. *Never* on +** a full-screen startup or resume. The font is loaded so that it will be +** available for full-screen text mode, but easier to load when windowed. +** Remember a mode change will load the corect font. +*/ +VOID loadNativeBIOSfont IFN1( int, vgaHeight ) +{ + sys_addr fontadd; // location of font + UTINY *regenptr; // destination in video + int cellsize; // individual character size + int skip; // gap between characters + int loop, pool; + UINT OutputCP; + + + /* + ** ordered this way as 80x50 console is default + ** VGA_HEIGHT_4 = 50 + ** VGA_HEIGHT_3 = 43 + ** VGA_HEIGHT_2 = 28 + ** VGA_HEIGHT_1 = 25 + ** VGA_HEIGHT_0 = 22 + */ + if (vgaHeight == VGA_HEIGHT_4 || vgaHeight == VGA_HEIGHT_3){ + cellsize = 8; + fontadd = GET_BIOS_FONT_ADDRESS(F8x8pt1); + }else + if (vgaHeight == VGA_HEIGHT_2){ + cellsize = 14; + fontadd = GET_BIOS_FONT_ADDRESS(F8x14); + }else{ + cellsize = 16; + fontadd = GET_BIOS_FONT_ADDRESS(F8x16); + } + + // set Int 43 to point to font + sas_storew(0x43 * 4, (word)(fontadd & 0xffff)); + sas_storew(0x43 * 4 + 2, (word)(fontadd >> 4 & 0xf000)); + +/* BUGBUG, williamh + We should have set int43 to the new font read from the CPI font. + This would require at least 4KB buffer in real mode address space. + The question is who is going to use this vector? So far, we haven't found + any applications use the vector(ROM BIOS is okay because the set video mode + function will reset the font and our new font will be lost anyway). + +*/ + + if (!sc.Registered || (OutputCP = GetConsoleOutputCP()) == 437 || + !LoadCPIFont(OutputCP, (WORD)8, (WORD)cellsize)) { + // now load it into the regen memory. We load it in at a0000 where + // an app will have to get to it. Luckily, this means we don't + // conflict with the text on the screen + + skip = 32 - cellsize; + + regenptr = (half_word *)0xa0000; + + if (cellsize == 8) /* 8x8 font comes in two halves */ + { + for (loop = 0; loop < 128; loop++) + { + for (pool = 0; pool < cellsize; pool++) + *regenptr++ = *(UTINY *)fontadd++; + regenptr += skip; + } + fontadd = GET_BIOS_FONT_ADDRESS(F8x8pt2); + for (loop = 0; loop < 128; loop++) + { + for (pool = 0; pool < cellsize; pool++) + *regenptr++ = *(UTINY *)fontadd++; + regenptr += skip; + } + } + else + { + for (loop = 0; loop < 256; loop++) + { + for (pool = 0; pool < cellsize; pool++) + *regenptr++ = *(UTINY *)fontadd++; + regenptr += skip; + } + } + } +} /* end of loadNativeBIOSfont() */ + +/* this function loads font data from EGA.CPI file located at %systemroot%\system32. + It is the same file console server used to load ROM font when the video + is in full screen. This function covers code page 437(ROM default). However, + the caller should make its best decision to call this function if the + output code page is not 437. This function doesn't care what code page + was provided. + The font size are limitted to(an assumption made by nt video driver and + the console server): + ** width must be 8 pixels. + ** Height must less or equal to 16 pixels. + +*/ + + + +BOOL LoadCPIFont(UINT CodePageID, WORD FontWidth, WORD FontHeight) +{ + BYTE Buffer[16 * 256]; + DWORD dw, BytesRead, FilePtr; + BYTE *VramAddr, *pSrc; + DWORD nChars; + PCPIFILEHEADER pCPIFileHeader = (PCPIFILEHEADER)Buffer; + PCPICODEPAGEHEADER pCPICodePageHeader = (PCPICODEPAGEHEADER) Buffer; + PCPICODEPAGEENTRY pCPICodePageEntry = (PCPICODEPAGEENTRY) Buffer; + PCPIFONTHEADER pCPIFontHeader = (PCPIFONTHEADER) Buffer; + PCPIFONTDATA pCPIFontData = (PCPIFONTDATA) Buffer; + BOOL bDOSCPI = FALSE; + HANDLE hCPIFile; + + /* max font height is 16 pixels and font width must be 8 pixels */ + if (FontHeight > 16 || FontWidth != 8) + return FALSE; + dw = GetSystemDirectoryA((CHAR *)Buffer, sizeof(Buffer)); + if (dw == 0 || dw + CPI_FILENAME_LENGTH > sizeof(Buffer)) + return FALSE; + RtlMoveMemory(&Buffer[dw], CPI_FILENAME, CPI_FILENAME_LENGTH); + // the file must be opened in READONLY mode or the CreateFileA will fail + // because the console sevrer always keeps an opened handle to the file + // and the file is opened READONLY. + + hCPIFile = CreateFileA(Buffer, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + if (hCPIFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!ReadFile(hCPIFile, Buffer, sizeof(CPIFILEHEADER), &BytesRead, NULL) || + BytesRead != sizeof(CPIFILEHEADER)) { + CloseHandle(hCPIFile); + return FALSE; + } + if (memcmp(pCPIFileHeader->Signature, CPI_SIGNATURE_NT, CPI_SIGNATURE_LENGTH)) + { + if (memcmp(pCPIFileHeader->Signature, CPI_SIGNATURE_DOS,CPI_SIGNATURE_LENGTH)) + { + CloseHandle(hCPIFile); + return FALSE; + } + else + bDOSCPI = TRUE; + } + + // move the file pointer to the code page table header + FilePtr = pCPIFileHeader->OffsetToCodePageHeader; + if (SetFilePointer(hCPIFile, FilePtr, NULL, FILE_BEGIN) == (DWORD) -1){ + CloseHandle(hCPIFile); + return FALSE; + } + + if (!ReadFile(hCPIFile, Buffer, sizeof(CPICODEPAGEHEADER), &BytesRead, NULL) || + BytesRead != sizeof(CPICODEPAGEHEADER)) { + CloseHandle(hCPIFile); + return FALSE; + } + // how many code page entries in the file + dw = pCPICodePageHeader->NumberOfCodePages; + FilePtr += BytesRead; + + // serach for the specific code page + while (dw > 0 && + ReadFile(hCPIFile, Buffer, sizeof(CPICODEPAGEENTRY), &BytesRead, NULL) && + BytesRead == sizeof(CPICODEPAGEENTRY)) { + if (pCPICodePageEntry->CodePageID == CodePageID) + break; + if (dw > 1) { + if (!bDOSCPI) + FilePtr += pCPICodePageEntry->OffsetToNextCodePageEntry; + else + FilePtr = pCPICodePageEntry->OffsetToNextCodePageEntry; + + if (SetFilePointer(hCPIFile, FilePtr, NULL, FILE_BEGIN) == (DWORD) -1) { + CloseHandle(hCPIFile); + return FALSE; + } + } + dw--; + } + if (dw == 0) { + CloseHandle(hCPIFile); + return FALSE; + } + // seek to the font header for the code page + if (!bDOSCPI) + FilePtr += pCPICodePageEntry->OffsetToFontHeader; + else + FilePtr = pCPICodePageEntry->OffsetToFontHeader; + if (SetFilePointer(hCPIFile, FilePtr, NULL, FILE_BEGIN) == (DWORD) -1) { + CloseHandle(hCPIFile); + return FALSE; + } + if (!ReadFile(hCPIFile, Buffer, sizeof(CPIFONTHEADER), &BytesRead, NULL) || + BytesRead != sizeof(CPIFONTHEADER)){ + CloseHandle(hCPIFile); + return FALSE; + } + // number of fonts with the specific code page + dw = pCPIFontHeader->NumberOfFonts; + + while(dw != 0 && + ReadFile(hCPIFile, Buffer, sizeof(CPIFONTDATA), &BytesRead, NULL) && + BytesRead == sizeof(CPIFONTDATA)) + { + if (pCPIFontData->FontHeight == FontHeight && + pCPIFontData->FontWidth == FontWidth) + { + nChars = pCPIFontData->NumberOfCharacters; + if (ReadFile(hCPIFile, Buffer, nChars * FontHeight, &BytesRead, NULL) && + BytesRead == nChars * FontHeight) + break; + else { + CloseHandle(hCPIFile); + return FALSE; + } + } + else { + if (SetFilePointer(hCPIFile, + (DWORD)pCPIFontData->NumberOfCharacters * (DWORD)pCPIFontData->FontHeight, + NULL, + FILE_CURRENT) == (DWORD) -1) { + CloseHandle(hCPIFile); + return FALSE; + } + dw--; + } + } + if (dw != 0) { + VramAddr = (BYTE *)0xa0000; + pSrc = Buffer; + for(dw = nChars; dw > 0; dw--) { + RtlMoveMemory(VramAddr, pSrc, FontHeight); + pSrc += FontHeight; + // font in VRAM is always 32 bytes + VramAddr += 32; + } + return TRUE; + } + return FALSE; +} +#endif /* X86GFX */ + +/* +*************************************************************************** +** calcScreenParams(), setup our screen screen parameters as determined +** by current Console state. +** Called from ConsoleInit() and DoFullScreenResume(). +** Returns current character height (8,14,16) and lines (22-50). +** Tim Jan 93, extracted common code from init and resume funx. +*************************************************************************** +*/ +GLOBAL VOID calcScreenParams IFN2( USHORT *, pCharHeight, USHORT *, pVgaHeight ) +{ + USHORT consoleWidth, + consoleHeight, + vgaHeight, + charHeight, + scanLines; + half_word temp; + + /* Get console information. */ + if (!GetConsoleScreenBufferInfo(sc.OutputHandle, &ConsBufferInfo)) + ErrorExit(); + + /* Now sync the SoftPC screen to the console. */ + if (sc.ScreenState == WINDOWED) + { + consoleWidth = ConsBufferInfo.srWindow.Right - + ConsBufferInfo.srWindow.Left + 1; + consoleHeight = ConsBufferInfo.srWindow.Bottom - + ConsBufferInfo.srWindow.Top + 1; + } +#ifdef X86GFX + else /* FULLSCREEN */ + { + if (!GetConsoleHardwareState(sc.OutputHandle, + &startUpResolution, + &startUpFontSize)) + ErrorExit(); + consoleWidth = startUpResolution.X / startUpFontSize.X; + consoleHeight = startUpResolution.Y / startUpFontSize.Y; + } +#endif + + /* + * Set the display to the nearest VGA text mode size, which is one of + * 80x22, 80x25, 80x28, 80x43 or 80x50. + */ + if (consoleHeight <= MID_VAL(VGA_HEIGHT_0, VGA_HEIGHT_1)) + { + /* 22 lines */ + vgaHeight = VGA_HEIGHT_0; + scanLines = 351; + charHeight = 16; + } + else if (consoleHeight <= MID_VAL(VGA_HEIGHT_1, VGA_HEIGHT_2)) + { + /* 25 lines */ + vgaHeight = VGA_HEIGHT_1; + scanLines = 399; + charHeight = 16; + } + else if (consoleHeight <= MID_VAL(VGA_HEIGHT_2, VGA_HEIGHT_3)) + { + /* 28 lines */ + vgaHeight = VGA_HEIGHT_2; + scanLines = 391; + charHeight = 14; + } + else if (consoleHeight <= MID_VAL(VGA_HEIGHT_3, VGA_HEIGHT_4)) + { + /* 43 lines */ + vgaHeight = VGA_HEIGHT_3; + scanLines = 349; + charHeight = 8; + } + else + { + /* 50 lines */ + vgaHeight = VGA_HEIGHT_4; + scanLines = 399; + charHeight = 8; + } + + if (sc.ScreenState == WINDOWED) + { + /* The app may have shutdown in a gfx mode - force text mode back */ + if (blocked_in_gfx_mode) + { + low_set_mode(3); + inb(EGA_IPSTAT1_REG,&temp); + outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE); /* re-enable video */ + (*choose_display_mode)(); + blocked_in_gfx_mode = FALSE; + } + /* + * Set screen height appropriately for current window size. + * Now call video routine to set the character height, updating the + * BIOS RAM as it does so. + */ + set_screen_height_recal( scanLines ); /* Tim Oct 92 */ + recalc_text(charHeight); + + /* badly written apps assume 25 line mode page len is 4096 */ + if (vgaHeight == 25) + sas_storew_no_check(VID_LEN, 0x1000); +#ifdef X86GFX + loadNativeBIOSfont( vgaHeight ); +#endif /* X86GFX */ + + } +#ifdef X86GFX + else /* FULLSCREEN */ + { + // Can't see why we wouldn't want this for resume too. + // set_char_height( startUpFontSize.Y ); /* Tim Oct 92 */ + + /* clear this condition on fullscreen resume */ + blocked_in_gfx_mode = FALSE; + + /* + ** Adjust height appropriately, Tim September 92. + ** In full-screen lines is 21 cos 22x16=352, slightly too big. + */ + if( vgaHeight==22 ) + vgaHeight = 21; + charHeight = startUpFontSize.Y; + sas_store_no_check(ega_char_height, (half_word) charHeight); + sas_store_no_check(vd_rows_on_screen, (half_word) (vgaHeight - 1)); + /* compatibility with bios 80x25 startup */ + if (vgaHeight == 25) + sas_storew_no_check(VID_LEN, 0x1000); + else + sas_storew_no_check(VID_LEN, (word) ((vgaHeight + 1) * + sas_w_at_no_check(VID_COLS) * 2)); + } +#endif /* X86GFX */ + sas_storew_no_check(VID_COLS, 80); // fixup from 40 char shutdown + *pCharHeight = charHeight; + *pVgaHeight = vgaHeight; + +} /* end of calcScreenParams() */ + +/*************************************************************************** + * Function: * + * ConsoleInit * + * * + * Description: * + * Does all the graphics work required on SoftPC start-up. * + * Will split or modify later to accomodate the SCS initialisation * + * that loses the config.sys etc output. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID ConsoleInit(VOID) +{ + USHORT charHeight, vgaHeight, cursorLine, topLine; + + note_entrance0("ConsoleInit"); + +#ifdef X86GFX + + /* Now GetROMsMapped called from config after sas_init */ + + /* + * Set emulation to a known state when starting up windowed. This has to + * be done after the ROMS are mapped but before we start to look at + * things like BIOS variables. + */ + GfxReset(); + +#endif + initTextSection(); + + /* + * Set up input focus details (we do it here as the fullscreen stuff + * is what is really interested in it). + */ + sc.Focus = TRUE; + sc.FocusEvent = CreateEvent((LPSECURITY_ATTRIBUTES) NULL, + FALSE, + FALSE, + NULL); + +#ifdef X86GFX +#ifdef SEPARATE_DETECT_THREAD + /* Create screen state transition detection thread. */ + CreateDetectThread(); +#endif /* SEPARATE_DETECT_THREAD */ +#endif /* X86GFX */ + + /* + * We don't want to call paint routines until config.sys processed or if + * the monitor is writing directly to the frame buffer (fullscreen), so... + */ + disableUpdates(); + + /* + ** Get console window size and set up our stuff accordingly. + */ + calcScreenParams( &charHeight, &vgaHeight ); + + StartupCharHeight = charHeight; +#ifdef X86GFX + if( sc.ScreenState != WINDOWED ) + { + /* + * Do we need to update the emulation? If we don't do this here then + * a later state dump of the VGA registers to the VGA emulation may + * ignore an equal value of the char height and get_chr_height() will + * be out of step. + */ + if (get_char_height() != startUpFontSize.Y) + { + half_word newht; + + outb(EGA_CRTC_INDEX, 9); /* select char ht reg */ + inb(EGA_CRTC_DATA, &newht); /* preserve current top 3 bits */ + newht = (newht & 0xe0) | (startUpFontSize.Y & 0x1f); + outb(EGA_CRTC_DATA, newht); + } + set_char_height( startUpFontSize.Y ); /* Tim Oct 92 */ + + /* + * Select a graphics screen buffer so we get mouse coordinates in + * pixels. + */ + //SelectMouseBuffer(); //Tim. moved to nt_std_handle_notification(). + + /* + * Prevent mode change happening to ensure dummy paint funcs + * are kept. (mode change set from bios mode set up). + */ + set_mode_change_required(FALSE); + } +#endif //X86GFX + + /* + * Work out the top line to be displayed in the VGA window, which is line + * zero of the console unless the cursor would not be displayed, in which + * case the window is moved down until the cursor is on the bottom line. + */ + cursorLine = ConsBufferInfo.dwCursorPosition.Y; + if (cursorLine < vgaHeight) + topLine = 0; + else + topLine = cursorLine - vgaHeight + (SHORT) 1; + + ConVGAHeight = vgaHeight; + ConTopLine = topLine; + + ConsoleInitialised = TRUE; +} + + +/*************************************************************************** + * Function: * + * GfxReset * + * * + * Description: * + * Called from ConsoleInit to program up the vga hardware into some * + * known state. This compensates on the X86 for not initialising via * + * our bios. Essential for windowed running, but probably needed * + * for the what-mode-am-i-in stuff as well. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID GfxReset(VOID) +{ +#ifdef X86GFX + half_word temp; + DWORD flags; + + /* Check to see if we are currently running windowed or full-screen. */ + if (!GetConsoleDisplayMode(&flags)) + ErrorExit(); + savedScreenState = sc.ScreenState = (flags & CONSOLE_FULLSCREEN_HARDWARE) ? + FULLSCREEN : WINDOWED; + + /* Do windowed specific stuff. */ + if(sc.ScreenState == WINDOWED) + { + /* Don't need this now cos we use our video BIOS in windowed */ + /* Tim August 92: low_set_mode(3); */ + /* sas_fillsw(0xb8000, 0x0720, 16000); */ + inb(EGA_IPSTAT1_REG,&temp); + + outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE); /* re-enable video */ + + /* Turn off the VTRACE interrupt, enabled by low_set_mode(3) + this is a dirty hack and must be fixed properly */ + + ega_int_enable = 0; + } + +#endif +} + +/*************************************************************************** + * Function: * + * ResetConsoleState * + * * + * Description: * + * Attempts to put the console window back to the state in which * + * it started up. * + * * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID ResetConsoleState(VOID) +{ +#ifdef X86GFX + /* + * Table of valid hardware states to be passed to + * SetConsoleHardwareState. NOTE: this table is a copy of a static table + * in SrvSetConsoleHardwareState, and so must be updated if that table + * changes. + */ + SAVED HARDWARE_STATE validStates[] = + { + ///Now 21{ 22, { 640, 350 }, { 8, 16 } }, /* 80 x 22 mode. */ + { 21, { 640, 350 }, { 8, 16 } }, /* 80 x 21 mode. */ + { 25, { 720, 400 }, { 8, 16 } }, /* 80 x 25 mode. */ + { 28, { 720, 400 }, { 8, 14 } }, /* 80 x 28 mode. */ + { 43, { 640, 350 }, { 8, 8 } }, /* 80 x 43 mode. */ +#define MODE_50_INDEX 4 + { 50, { 720, 400 }, { 8, 8 } } /* 80 x 50 mode. */ + }; + COORD cursorPos; + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + ULONG i, + j, + videoWidth, + mode, + tableLen; + half_word *from, + *videoLine, + currentPage, + misc; + static COORD screenRes; /* value provided by GetConsHwState() */ + static COORD fontSize; /* value provided by GetConsHwState() */ + + PCHAR_INFO to; + ULONG videoHeight, + nChars; + COORD bufferCoord, + bufferSize; + SMALL_RECT writeRegion; + +#endif /* X86GFX */ + SMALL_RECT newWin; + BOOL itfailed = FALSE; + +#ifdef X86GFX + if (sc.ScreenState == WINDOWED) + { +#endif /* X86GFX */ + + closeGraphicsBuffer(); + + if (StreamIoSwitchOn && !host_stream_io_enabled) { + /* restore screen buffer and window size */ + SetConsoleScreenBufferSize(sc.OutputHandle, sc.ConsoleBuffInfo.dwSize); + newWin.Top = newWin.Left = 0; + newWin.Bottom = sc.ConsoleBuffInfo.srWindow.Bottom - + sc.ConsoleBuffInfo.srWindow.Top; + newWin.Right = sc.ConsoleBuffInfo.srWindow.Right - + sc.ConsoleBuffInfo.srWindow.Left; + SetConsoleWindowInfo(sc.OutputHandle, TRUE, &newWin); + } + /* + ** Tim September 92, don't resize window on way out of DOS app cos + ** MS (Sudeep) said so. Don't want to do the associated recalc_text() + ** either. + ** This keeps the window re-sizing issue nice and simple, but there'll + ** be people who don't like having a DOS window size forced upon them. + */ +#if 0 + /* Now resize the window to start-up size. */ + newWin.Top = newWin.Left = 0; + newWin.Bottom = ConsBufferInfo.srWindow.Bottom - + ConsBufferInfo.srWindow.Top; + newWin.Right = ConsBufferInfo.srWindow.Right - + ConsBufferInfo.srWindow.Left; + + if(!SetConsoleWindowInfo(sc.OutputHandle, TRUE, &newWin)) + itfailed = TRUE; + + if(!SetConsoleScreenBufferSize(sc.OutputHandle,ConsBufferInfo.dwSize)) + ErrorExit(); + if (itfailed) //try 'it' again... + if(!SetConsoleWindowInfo(sc.OutputHandle, TRUE, &newWin)) + ErrorExit(); + + /* + * Now call video routine to set the character height, updating the + * BIOS RAM as it does so. + */ + recalc_text(StartupCharHeight); +#endif //Zero + +#if 0 + /* williamh. If we really want to do the following thing, + we have to copy regen to console buffer. + since we are runniing in windowed TEXT mode + the console always has our up-to-date regen + content, the following actually is not necessary + It worked before taking this out it because console + doesn't verify the parameters we passed. No console + has the checking and we are in trouble if we continue + to do so. + */ + + /* Clear the undisplayed part of the console buffer. */ + bufferSize.X = MAX_CONSOLE_WIDTH; + bufferSize.Y = MAX_CONSOLE_HEIGHT; + videoHeight = (SHORT) (sas_hw_at_no_check(vd_rows_on_screen) + 1); + to = consoleBuffer + bufferSize.X * videoHeight; + nChars = bufferSize.X * ( bufferSize.Y - videoHeight ); + + while (nChars--) + { + to->Char.AsciiChar = 0x20; + to->Attributes = 7; + to++; + } + bufferCoord.X = 0; + bufferCoord.Y = (SHORT)videoHeight; + writeRegion.Left = 0; + writeRegion.Top = (SHORT)videoHeight; + writeRegion.Right = MAX_CONSOLE_WIDTH-1; + writeRegion.Bottom = bufferSize.Y-1; + if (!WriteConsoleOutput(sc.OutputHandle, + consoleBuffer, + bufferSize, + bufferCoord, + &writeRegion)) + ErrorExit(); +#endif + /* + ** Tim, September 92. Put the Console cursor to the same place as the + ** SoftPC cursor. We already do this in full-screen text mode below. + ** Specifcally to fix weird cursor position problem with 16-bit nmake, + ** but seems like a good safety idea anyway. + */ + getVDMCursorPosition(); + + doNullRegister(); /* revert console back to ordinary window */ + +#ifdef X86GFX + } + else /* FULLSCREEN */ + { + /* + * If SoftPC blocks in a text mode, sync console srceen buffer to regen + * area. + */ + if (getModeType() == TEXT) + { + /* Get the current screen buffer info. */ + if (!GetConsoleScreenBufferInfo(sc.OutputHandle, &bufferInfo)) + ErrorExit(); + + /* Get nearest screen size SetConsoleHardwareState will allow. */ + tableLen = sizeof(validStates) / sizeof(HARDWARE_STATE); + for (mode = 0; mode < tableLen; mode++) + if (validStates[mode].LinesOnScreen == + bufferInfo.srWindow.Bottom - bufferInfo.srWindow.Top + 1) + break; + + /* Set it to 50 line mode if we had a funny number of lines. */ + if (mode == tableLen) + { + assert0(FALSE, + "Non standard lines on blocking - setting 50 lines"); + mode = MODE_50_INDEX; + } + + /* + ** Tim September 92, if the console hardware state is the same as + ** we are about to set it, do not bother setting it. + ** This should stop the screen from flashing. + */ + if( !GetConsoleHardwareState(sc.OutputHandle, + &screenRes, + &fontSize) ) + assert1( NO,"VDM: GetConsHwState() failed:%#x",GetLastError() ); + + /* Sync the console to the regen buffer. */ + currentPage = sas_hw_at_no_check(vd_current_page); + vga_misc_inb(0x3cc, &misc); + if (misc & 1) // may be mono mode + videoLine = (half_word *) CGA_REGEN_START + + (VIDEO_PAGE_SIZE * currentPage); + else + videoLine = (half_word *) MDA_REGEN_START + + (VIDEO_PAGE_SIZE * currentPage); + to = consoleBuffer; + videoWidth = sas_w_at_no_check(VID_COLS); + videoHeight = (SHORT) (sas_hw_at_no_check(vd_rows_on_screen) + 1); + bufferSize.X = MAX_CONSOLE_WIDTH; + bufferSize.Y = MAX_CONSOLE_HEIGHT; + if (bufferSize.X * bufferSize.Y > MAX_CONSOLE_SIZE) + { + assert1(FALSE, "Buffer size, %d, too large", + bufferSize.X * bufferSize.Y); + ErrorExit(); + } + for (i = 0; i < videoHeight; i++) + { + from = videoLine; + for (j = 0; j < videoWidth; j++) + { + to->Char.AsciiChar = *from++; + to->Attributes = *from++; + to++; + } + for (; j < (ULONG)bufferSize.X; j++) + { + to->Char.AsciiChar = 0x20; + to->Attributes = 7; + to++; + } + videoLine += videoWidth * 2; + } + for (; i < (ULONG)bufferSize.Y; i++) + for (j = 0; j < (ULONG)bufferSize.X; j++) + { + to->Char.AsciiChar = 0x20; + to->Attributes = 7; + to++; + } + bufferCoord.X = bufferCoord.Y = 0; + writeRegion.Left = writeRegion.Top = 0; + writeRegion.Right = bufferSize.X - 1; + writeRegion.Bottom = bufferSize.Y - 1; + + doNullRegister(); /* revert back to normal console */ + + if( screenRes.X != validStates[mode].Resolution.X || + screenRes.Y != validStates[mode].Resolution.Y || + fontSize.X != validStates[mode].FontSize.X || + fontSize.Y != validStates[mode].FontSize.Y || + sas_hw_at_no_check(VID_COLS) == 40 || + fontSize.Y != sas_hw_at_no_check(ega_char_height)) + { + /* Set up the screen. */ + if( !SetConsoleHardwareState( sc.OutputHandle, + validStates[mode].Resolution, + validStates[mode].FontSize) ){ + /* + ** Tim Sept 92, attempt a recovery. + */ + assert1( NO, "VDM: SetConsoleHwState() failed:%#x", + GetLastError() ); + } + } + + + /* put VDM screen onto console screen */ + if (!WriteConsoleOutput(sc.OutputHandle, + consoleBuffer, + bufferSize, + bufferCoord, + &writeRegion)) + ErrorExit(); + +#if 0 //STF removed with new mouse stuff?? + /* + ** Tim, September 92. + ** Try this after the WriteConsoleOutput(), can now copy the + ** right stuff from video memory to console. + ** For mouse purposes we have selected a graphics buffer, so now + ** we must reselect the text buffer. + */ + if (!SetConsoleActiveScreenBuffer(sc.OutputHandle)) + ErrorExit(); +#endif //STF + + /* + * Get the cursor position from the BIOS RAM and tell the + * console. + * Set up variables getVDMCursorPosition() needs. Tim Jan 93. + */ + sc.PC_W_Height = screenRes.Y; + sc.CharHeight = fontSize.Y; + getVDMCursorPosition(); + } + else /* GRAPHICS */ + { + /* + ** A tricky issue. If we were just in a full-screen graphics + ** mode, we are just about to lose the VGA state and can't get + ** it back very easily. So do we pretend we are still in the + ** graphics mode or pretend we are in a standard text mode? + ** Seems like standard text mode is more sensible. Tim Feb 93. + */ + sas_store_no_check( vd_video_mode, 0x3 ); + blocked_in_gfx_mode = TRUE; + +#if 0 //STF removed with new mouse stuff?? + /* + ** Tim, September 92, think we want one of these here too. + ** Change to the normal console text buffer. + */ + if (!SetConsoleActiveScreenBuffer(sc.OutputHandle)) + ErrorExit(); +#endif //STF + + /* Get the current screen buffer info. */ + if (!GetConsoleScreenBufferInfo(sc.OutputHandle, &bufferInfo)) + ErrorExit(); + + /* Get nearest screen size SetConsoleHardwareState will allow. */ + tableLen = sizeof(validStates) / sizeof(HARDWARE_STATE); + for (mode = 0; mode < tableLen; mode++) + if (validStates[mode].LinesOnScreen == + bufferInfo.srWindow.Bottom - bufferInfo.srWindow.Top + 1) + break; + + /* Set it to 50 line mode if we had a funny number of lines. */ + if (mode == tableLen) + { + assert0(FALSE, + "Non standard lines on blocking - setting 50 lines"); + mode = MODE_50_INDEX; + } + + /* Clear the console buffer. */ + bufferSize.X = MAX_CONSOLE_WIDTH; + bufferSize.Y = MAX_CONSOLE_HEIGHT; + nChars = bufferSize.X * bufferSize.Y; + if (nChars > MAX_CONSOLE_SIZE) + { + assert1(FALSE, "Buffer size, %d, too large", nChars); + ErrorExit(); + } + to = consoleBuffer; + while (nChars--) + { + to->Char.AsciiChar = 0x20; + to->Attributes = 7; + to++; + } + bufferCoord.X = bufferCoord.Y = 0; + writeRegion.Left = writeRegion.Top = 0; + writeRegion.Right = MAX_CONSOLE_WIDTH-1; + writeRegion.Bottom = bufferSize.Y-1; + + doNullRegister(); /* revert back to normal console */ + + if (!WriteConsoleOutput(sc.OutputHandle, + consoleBuffer, + bufferSize, + bufferCoord, + &writeRegion)) + ErrorExit(); + + /* Set the cursor to the top left corner. */ + cursorPos.X = 0; + cursorPos.Y = 0; + if (!SetConsoleCursorPosition(sc.OutputHandle, cursorPos)) + ErrorExit(); +#ifndef PROD + if (sc.ScreenState == WINDOWED) // transient switch?? + assert0(NO, "Mismatched screenstate on shutdown"); +#endif + + /* Set up the screen. */ + SetConsoleHardwareState(sc.OutputHandle, + validStates[mode].Resolution, + validStates[mode].FontSize); + } + /* + ** Tim September 92, close graphics screen buffer on way out when in + ** full-screen. + */ + closeGraphicsBuffer(); + } +#endif /* X86GFX */ + + /*Put console's cursor back to the shape it was on startup.*/ + SetConsoleCursorInfo(sc.OutputHandle, &StartupCursor); + + /* reset the current_* variables in nt_graph.c */ + resetWindowParams(); +} + + +#ifdef X86GFX + +/*************************************************************************** + * Function: * + * TextToGraphics * + * * + * Description: * + * Handles transitions from text to graphics modes when running * + * windowed. Waits until the window has input focus and then requests * + * a transition to full-screen operation as graphics modes cannot be * + * run in a window. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID TextToGraphics(VOID) +{ + DWORD flags; + SAVED COORD scrSize; + + /* Freeze until the window receives input focus. */ + //if (! sc.Focus ) //awaiting console fix. + if (GetForegroundWindow() != hWndConsole) + { + + FreezeWinTitle(); /* Add `-FROZEN' to the console title. */ + + /* Now wait until input focus is received. */ + waitForInputFocus(); + + UnFreezeWinTitle(); /* Remove frozen message */ + } + + /* + * We are about to go full-screen but there will be a delay while the + * detection thread does its hand-shaking. So disable screen writes before + * we switch to prevent inadvertent updates while running full-screen. + */ + disableUpdates(); + + /* + * Sanity Check for stress problem where forced fullscreen after INT 10 + * mode change has already started so can apparently go fullscreen twice. + */ + if (!GetConsoleDisplayMode(&flags)) + ErrorExit(); + + /* make sure we haven't been taken back fullscreen */ + if ((flags & CONSOLE_FULLSCREEN_HARDWARE) == CONSOLE_FULLSCREEN_HARDWARE) + { +#ifndef PROD + assert0(NO,"NTVDM:rejected fullscreen switch as console already FS"); +#endif + return; + } + + /* check for iconified FS console. Only under extreme conditions (stress) */ + if ((flags & CONSOLE_FULLSCREEN) == CONSOLE_FULLSCREEN) + { + SetForegroundWindow(hWndConsole); /* focus will send us back FS */ + } + else /* desktop window */ + { + /* The window now has input focus so request to go full-screen. */ + BiosModeChange = TRUE; + if (!SetConsoleDisplayMode(sc.OutputHandle, + CONSOLE_FULLSCREEN_MODE, + &scrSize)) + { + if (GetLastError() == ERROR_INVALID_PARAMETER) + { + RcErrorDialogBox(ED_INITFSCREEN, NULL, NULL); + } + else + { + ErrorExit(); + } + } + BiosModeChange = FALSE; + } +} + +/*************************************************************************** + * Function: * + * CheckForFullscreenSwitch * + * * + * Description: * + * Checks to see if there has been a transition between windowed and * + * fullscreen and does any console calls necessary. This is called * + * on a timer tick before the graphics tick code. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID CheckForFullscreenSwitch(VOID) +{ + half_word mode, + lines; + + if (sc.ScreenState == STREAM_IO) + return; + + /* + * Do any console calls relating to screen state changes. They have to be + * done now as they cannot be done on the same thread as the screen switch + * hand-shaking. + */ + if (sc.ScreenState != savedScreenState) + { + if (sc.ScreenState == WINDOWED) + { + if (sc.ModeType == TEXT) + { + + /* Remove frozen window indicator if necessary. */ + UnFreezeWinTitle(); + +#if 0 //STF removed with new mouse stuff?? + /* Revert to text buffer. */ + closeGraphicsBuffer(); /* Tim Oct 92 */ +#endif //STF + + /* Get Window to correct shape */ + textResize(); + + /* Enable screen updates. */ + enableUpdates(); + + /* + * Now get the image on the screen (timer updates currently + * disabled). + */ + (void)(*update_alg.calc_update)(); + + } + } + else /* FULLSCREEN */ + { + int cnt = 0; /* Counter to break out of the cursor off loop. */ + + /* Disable screen updates*/ + disableUpdates(); + + /* Disable mouse 'attached'ness if enabled */ + if (bPointerOff) + { + PointerAttachedWindowed = TRUE; + MouseDisplay(); + } + +#if 0 //STF removed with new mouse stuff + /* remove any graphics buffer from frozen screen */ + closeGraphicsBuffer(); +#endif + + /* Do mouse scaling */ + mode = sas_hw_at_no_check(vd_video_mode); + lines = sas_hw_at_no_check(vd_rows_on_screen) + 1; + SelectMouseBuffer(mode, lines); + + /* force mouse */ + ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER, AT_CPU_MOUSE_INT, 1); + + /* + * Now turn off console cursor - otherwise can ruin screen trying to + * draw system's cursor. The VDM will have to worry about the mouse + * image. + */ + // while(ShowConsoleCursor(sc.OutputHandle, FALSE) >=0 && cnt++ < 200); + } /* FULLSCREEN */ + + /* Update saved variable. */ + savedScreenState = sc.ScreenState; + } + /* Delayed Client Rect query */ + if (DelayedReattachMouse) + { + DelayedReattachMouse = FALSE; + MovePointerToWindowCentre(); + } +} + +/* +*************************************************************************** +** getNtScreenState() - return 0 for windowed, 1 for full-screen. +*************************************************************************** +** Tim July 92. +*/ +GLOBAL UTINY getNtScreenState IFN0() +{ + return( (UTINY) sc.ScreenState ); +} + +/* +*************************************************************************** +** hostModeChange() - called from video bios, ega_vide.c:ega_set_mode() +*************************************************************************** +** +** When changing to a graphics mode action the transition to full-screen if +** we are currently windowed. +** +** On entry AX should still contain the value when the video BIOS set mode +** function was called. +** Call to TextToGraphics() with parameter indicating whether we want a +** clear screen with the impending host video BIOS mode change. +** +** Return a boolean indicating to the real BIOS whether the mode change +** has occured. +** +** Tim August 92. +*/ +GLOBAL BOOL hostModeChange IFN0() +{ + half_word vid_mode; + + vid_mode = getAL() & 0x7f; + + if(getNtScreenState() == WINDOWED) + { + if (vid_mode > 3 && vid_mode != 7) + { + /* + * We have to tell the hand-shaking code the BIOS is causing + * the mode change so that it can do a BIOS mode change when + * the switch has been done. This has to be implemented as a + * global variable because the hand-shaking is on a different + * thread. + */ + TextToGraphics(); + // rapid Window to full screen and back cause this to fail, + // remove call since it will get done on the next timer + // event. 28-Feb-1993 Jonle + // SelectMouseBuffer(); + return( TRUE ); + } + else + return(FALSE); + } + else + return( FALSE ); + +} /* end hostModeChange() */ +#endif /* X86GFX */ + +/*************************************************************************** + * Function: * + * DoFullScreenResume * + * * + * Description: * + * Called by SCS to restart SoftPC when a DOS application restarts * + * after being suspended or starts up for the first time after SoftPC * + * has been booted by another application which has since terminated. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ + +GLOBAL VOID DoFullScreenResume(VOID) +{ + USHORT vgaHeight, height; +#ifndef X86GFX + PVOID pDummy; +#endif + +#ifdef X86GFX + DWORD flags; + + /* + ** Tim July 92. + ** Set sc.ScreenState, a windowed/full-screen transition might + ** have happenened when SoftPC was inactive. + ** Copied from GfxReset(). + */ + if( !GetConsoleDisplayMode(&flags) ) + ErrorExit(); + sc.ScreenState = (flags & CONSOLE_FULLSCREEN_HARDWARE) ? FULLSCREEN : WINDOWED; + + /* Put the regen memory in the correct state. */ + if (sc.ScreenState != savedScreenState) + { + if (sc.ScreenState == WINDOWED) + { + enableUpdates(); /* Tim September 92, allow graphics ticks */ + /* + ** Tim Jan 93. Get the next nt_graphics_tick() to decide + ** what the current display mode is, set the update and + ** paint funx appropriately and redraw the screen. + */ + set_mode_change_required( TRUE ); + + /* Ensure idling system enabled & reset */ + IDLE_ctl(TRUE); + IDLE_init(); + } + else + { + disableUpdates(); /* Tim September 92, stop graphics ticks */ + + /* Ensure idling system disabled as can't detect fullscreen idling*/ + IDLE_ctl(FALSE); + } + savedScreenState = sc.ScreenState; + } + + /* Select a graphics buffer for the mouse if we are running fullscreen. */ + if (sc.ScreenState == FULLSCREEN) + { + //SelectMouseBuffer(); //Tim. moved to nt_std_handle_notification(). + + /* Lose the regen memory. */ + LoseRegenMemory(); + } + + /* + ** Tim July 92: + ** set the KEYBOARD.SYS internal variable to 0 for windowed and + ** 1 for full-screen. + ** If a transition has happened when SoftPC was inactive we + ** need to get into the appropriate state. + */ + { + if( sc.ScreenState==WINDOWED ){ + sas_store_no_check( (int10_seg<<4)+useHostInt10, WINDOWED ); + }else{ + sas_store_no_check( (int10_seg<<4)+useHostInt10, FULLSCREEN ); + } + } +#endif /* X86GFX */ + + // re-register with console for fullscreen switching. + if( !RegisterConsoleVDM( VDMForWOW ? + CONSOLE_REGISTER_WOW : CONSOLE_REGISTER_VDM, +#ifdef X86GFX + hStartHardwareEvent, + hEndHardwareEvent, +#else + NULL, + NULL, +#endif + + NULL, // sectionname no longer used + 0, // sectionname no longer used + &stateLength, +#ifndef X86GFX + &pDummy, +#else + (PVOID *) &videoState, +#endif + NULL, // sectionname no longer used + 0, // sectionname no longer used + textBufferSize, + (PVOID *) &textBuffer + ) + ) + ErrorExit(); + +#ifdef X86GFX + sc.Registered = TRUE; + /* stateLength can be 0 if fullscreen is disabled in the console */ + if(stateLength) + RtlZeroMemory(videoState, sizeof(VIDEO_HARDWARE_STATE_HEADER)); +#else + /* + ** Create graphics buffer if we need one. Tim Oct 92. + */ + if( sc.ModeType==GRAPHICS ) + graphicsResize(); +#endif + /* + ** Tim September 92. + ** If window size is not suitable for a DOS app, snap-to-fit + ** appropriately. Put cursor in correct place. + ** Do the ConsoleInit() and nt_init_event_thread() type of things. + ** Leave full-screen as it was. + */ + if (sc.ScreenState != WINDOWED) { + /* Get console info, including the current cursor position. */ + if (!GetConsoleScreenBufferInfo(sc.OutputHandle, &ConsBufferInfo)) + ErrorExit(); + /* Hard-wired for f-s resume - needs to be set properly. */ + height = 8; + /* Set up BIOS variables etc. */ + setVDMCursorPosition( (UTINY)height, + &ConsBufferInfo.dwCursorPosition); + /* Copy the console buffer to the regen buffer. */ + copyConsoleToRegen(0, 0, VGA_WIDTH, (SHORT)ConVGAHeight); + } + + /* + ** Get console window size and set up our stuff accordingly. + */ + calcScreenParams( &height, &vgaHeight ); + + /* + ** Window resize code copied out of nt_graph.c:textResize(). + */ + { + resizeWindow( 80, vgaHeight ); + } + + /* Copy the console buffer to the regen buffer. */ + copyConsoleToRegen(0, 0, VGA_WIDTH, vgaHeight); + + /* + ** Make sure cursor is not below bottom line. + */ + if( ConsBufferInfo.dwCursorPosition.Y >= vgaHeight ){ + ConsBufferInfo.dwCursorPosition.Y = vgaHeight-1; + } + setVDMCursorPosition(( UTINY)height, &ConsBufferInfo.dwCursorPosition); + +} /* end of DoFullScreenResume() */ + +/*************************************************************************** + * Function: * + * GfxCloseDown * + * * + * Description: * + * Hook from host_terminate to ensure section closed so can then start* + * more VDMs. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID (Errors handled internally in CloseSection) * + * * + ***************************************************************************/ +GLOBAL VOID GfxCloseDown(VOID) +{ + /* Text and Video sections previously closed here... */ +} + +#ifdef X86GFX +/*************************************************************************** + * Function: * + * FreezeWinTitle * + * * + * Description: * + * Adds -FROZEN to the relevant console window title * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID FreezeWinTitle(VOID) +{ + CHAR title[MAX_TITLE_LEN],*ptr; + SHORT max; + ULONG len; + + if (WinFrozen) + return; + + // + // The buffer contains the string plus the terminating null. + // So keep the string length less the null in len. + // Console can fail this call with silly error codes in low memory cases + // or if original title contains dubious chars. + // + + len = strlen(szFrozenString); + + max = (SHORT) (MAX_TITLE_LEN - len); + if (!GetConsoleTitle(title, max)) + title[0] = '\0'; + + // + // Remove any trailing spaces or tabs from the title string + // + + if(len = strlen(title)) + { + ptr = title + len - 1; + while(*ptr == ' ' || *ptr == '\t') + *ptr-- = '\0'; + } + + // + // Add " - FROZEN" or the international equivalent to + // the end of the title string. + // + + strcat(title, szFrozenString); + if (!SetConsoleTitle(title)) + ErrorExit(); + WinFrozen = TRUE; + +} + +/*************************************************************************** + * Function: * + * UnFreezeWinTitle * + * * + * Description: * + * Removes -FROZEN from the relevant console window title * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID UnFreezeWinTitle(VOID) +{ + CHAR title[MAX_TITLE_LEN]; + ULONG len,orglen; + + if (! WinFrozen) + return; + + if (!GetConsoleTitle(title, MAX_TITLE_LEN)) + ErrorExit(); + + + // + // The buffer contains the string plus the terminating null. + // So keep the string length less the null in len. + // + + len = strlen(szFrozenString); + orglen = strlen(title); + title[orglen - len] = '\0'; + if (!SetConsoleTitle(title)) + ErrorExit(); + WinFrozen = FALSE; + + // + // Now that we're thawing, put the mouse menu item + // back into the system menu. + // Andy! + + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); +} +#endif + + +/* + * ========================================================================== + * Local Functions + * ========================================================================== + */ + +/*************************************************************************** + * Function: * + * enableUpdates * + * * + * Description: * + * Restarts the reflection of regen buffer updates to paint routines. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +VOID enableUpdates(VOID) +{ + enable_gfx_update_routines(); + ConsoleNoUpdates = FALSE; +} + +/*************************************************************************** + * Function: * + * disableUpdates * + * * + * Description: * + * Stops changes to the regen buffer being reflected to paint * + * routines. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +VOID disableUpdates(VOID) +{ + disable_gfx_update_routines(); + ConsoleNoUpdates = TRUE; +} + +/*************************************************************************** + * Function: * + * copyConsoleToRegen * + * * + * Description: * + * Copies the contents of the console buffer to the video regen * + * buffer. * + * * + * Parameters: * + * startCol - start column of console buffer * + * startLine - start line of console buffer * + * width - width of console buffer * + * height - height of console buffer * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +VOID copyConsoleToRegen(SHORT startCol, SHORT startLine, SHORT width, + SHORT height) +{ + CHAR_INFO *from; + COORD bufSize, + bufCoord; + LONG nChars; + SMALL_RECT readRegion; + + register half_word *to; +#ifdef X86GFX + half_word misc; + register half_word *vc; +#endif + + + /* Allocate the buffer to get the console data into */ + nChars = width * height; + assert0(nChars <= MAX_CONSOLE_SIZE, "Console buffer overflow"); + + /* Get the console data. */ + bufSize.X = width; + bufSize.Y = height; + bufCoord.X = 0; + bufCoord.Y = 0; + readRegion.Left = startCol; + readRegion.Top = startLine; + readRegion.Right = startCol + width - (SHORT) 1; + readRegion.Bottom = startLine + height - (SHORT) 1; + if (!ReadConsoleOutput(sc.OutputHandle, + consoleBuffer, + bufSize, + bufCoord, + &readRegion)) + ErrorExit(); + + /* Copy the console data to the regen buffer. */ + from = consoleBuffer; + +#ifndef X86GFX // on MIPS we actually want to write to the VGA bitplanes. + to = EGA_planes; + while(nChars--) + { + *to++ = from->Char.AsciiChar; + *to = (half_word) from->Attributes; + from++; + to += 3; // skipping interleaved font planes. + } + host_mark_screen_refresh(); +#else + + /* + * In V86 mode PC memory area is mapped to the bottom 1M of virtual memory, + * so the following is legal. + */ + vga_misc_inb(0x3cc, &misc); + if (misc & 1) // may be mono mode + to = (half_word *) CGA_REGEN_START; + else + to = (half_word *) MDA_REGEN_START; + + vc = (half_word *) video_copy; + + while (nChars--) + { + *to++ = *vc++ = from->Char.AsciiChar; + *to++ = *vc++ = (half_word) from->Attributes; + from++; + } +#endif +} + +/*************************************************************************** + * Function: * + * getVDMCursorPosition * + * * + * Description: * + * Gets the cursor position from BIOS variables and tells the console * + * where to place its cursor. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +VOID getVDMCursorPosition(VOID) +{ + half_word currentPage; + word cursorWord; + COORD cursorPos; + BOOL setok; + + /* Get the current video page. */ + currentPage = sas_hw_at_no_check(vd_current_page); + + /* Store cursor position in BIOS variables. */ + cursorWord = sas_w_at_no_check(VID_CURPOS + (currentPage * 2)); + + /* Set the console cursor. */ + cursorPos.X = (SHORT) (cursorWord & 0xff); + cursorPos.Y = (cursorWord >> 8) & (SHORT) 0xff; + + if ((sc.CharHeight * cursorPos.Y) > sc.PC_W_Height) + cursorPos.Y = (sc.PC_W_Height / sc.CharHeight) - 1; + + if( !stdoutRedirected ) { + setok = SetConsoleCursorPosition(sc.OutputHandle, cursorPos); + if (!setok) { + + if (GetLastError() != ERROR_INVALID_HANDLE) // ie. output redirected + ErrorExit(); + } + } +} + +/*************************************************************************** + * Function: * + * setVDMCursorPosition * + * * + * Description: * + * Positions SoftPC's cursor, setting the relevant BIOS variables. * + * * + * Parameters: * + * height - the current character height * + * cursorPos - the coordinates of the cursor * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +VOID setVDMCursorPosition(UTINY height, PCOORD cursorPos) +{ + CONSOLE_CURSOR_INFO cursorInfo; + ULONG port6845, + cursorStart, + cursorEnd, + colsOnScreen, + videoLen, + pageOffset, + cursorWord; + UTINY currentPage; + + /* Get cursor size. */ + if(!GetConsoleCursorInfo(sc.OutputHandle, &cursorInfo)) + ErrorExit(); + + /* Work out cursor start and end pixels. */ + cursorStart = height - (height * cursorInfo.dwSize / 100); + if (cursorStart == height) + cursorStart--; + cursorEnd = height - 1; + + if (sc.ScreenState == WINDOWED) + { + + /* Pass cursor size to video ports. */ + port6845 = sas_w_at_no_check(VID_INDEX); + outb((io_addr) port6845, R10_CURS_START); + outb((io_addr) (port6845 + 1), (half_word) cursorStart); + outb((io_addr) port6845, R11_CURS_END); + outb((io_addr) (port6845 + 1), (half_word) cursorEnd); + } + + /* Get the current video page. */ + currentPage = sas_hw_at_no_check(vd_current_page); + + /* Set BIOS variables. */ + sas_storew_no_check(VID_CURMOD, + (word) ((cursorStart << 8) | (cursorEnd & 0xff))); + + /* Work out cursor position. */ + colsOnScreen = sas_w_at_no_check(VID_COLS); + videoLen = sas_w_at_no_check(VID_LEN); + pageOffset = cursorPos->Y * colsOnScreen * 2 + (cursorPos->X << 1); + cursorWord = (currentPage * videoLen + pageOffset) / 2; + + if (sc.ScreenState == WINDOWED) + { + + /* Send cursor position to video ports. */ + outb((io_addr) port6845, R14_CURS_ADDRH); + outb((io_addr) (port6845 + 1), (half_word) (cursorWord >> 8)); + outb((io_addr) port6845, R15_CURS_ADDRL); + outb((io_addr) (port6845 + 1), (half_word) (cursorWord & 0xff)); + } + + /* Store cursor position in BIOS variables. */ + sas_storew_no_check(VID_CURPOS + (currentPage * 2), + (word) ((cursorPos->Y << 8) | (cursorPos->X & 0xff))); + + if (sc.ScreenState == WINDOWED) + { +#ifdef MONITOR + resetNowCur(); /* reset static vars holding cursor pos. */ +#endif + do_new_cursor(); /* make sure the emulation knows about it */ + } +} + +VOID waitForInputFocus() +{ + if (WaitForSingleObject(sc.FocusEvent, INFINITE)) + ErrorExit(); +} + +VOID AddTempIVTFixups() +{ + /* BOP 17, IRET */ + UTINY code[] = { 0xc4, 0xc4, 0x17, 0xcf }; + + //location is random but should be safe until DOS is initialised!!! + sas_stores(0x40000, code, sizeof(code)); // new Int 17 code + sas_storew(0x17*4, 0); // Int 17h offset + sas_storew((0x17*4) + 2, 0x4000); // Int 17h segment +} + +/*************************************************************************** + * Function: * + * getModeType * + * * + * Description: * + * Look up video mode to determine whether the VGA current mode is * + * graphics or text. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * int - TEXT or GRAPHICS. * + * * + ***************************************************************************/ +int getModeType(VOID) +{ + half_word mode; + int modeType; + + mode = sas_hw_at_no_check(vd_video_mode); + switch(mode) + { + case 0: + case 1: + case 2: + case 3: + case 7: + case 0x20: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + modeType = TEXT; + break; + default: + modeType = GRAPHICS; + break; + } + return(modeType); +} + +#ifdef X86GFX +/*************************************************************************** + * Function: * + * host_check_mouse_buffer * + * * + * Description: * + * Called when an INT 10h, AH = 11h is being executed, this function * + * checks to see if the number of lines on the screen for a text mode * + * has changed and if so selects a new mouse buffer. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID host_check_mouse_buffer(VOID) +{ + half_word mode, + sub_func, + font_height, + text_lines; + IU16 scan_lines; + + /* Get the current video mode. */ + mode = sas_hw_at_no_check(vd_video_mode); +#ifdef V7VGA + if (mode > 0x13) + mode += 0x4c; + else if ((mode == 1) && (extensions_controller.foreground_latch_1)) + mode = extensions_controller.foreground_latch_1; +#endif /* V7VGA */ + + /* + * Check to see if we are in a text mode whose mouse virtual coordinates + * are affected by the number of lines on the screen. + */ + if ((mode == 0x2) || (mode == 0x3) || (mode == 0x7)) + { + + /* Work out the font height being set. */ + sub_func = getAL(); + switch (sub_func) + { + case 0x10: + font_height = getBH(); + break; + case 0x11: + font_height = 14; + break; + case 0x12: + font_height = 8; + break; + case 0x14: + font_height = 16; + break; + default: + + /* + * The above are the only functions that re-program the no. of lines + * on the screen, so do nothing if we have something else. + */ + return; + } + + /* Get the number of scan lines for this mode. */ + if(!(get_EGA_switches() & 1) && (mode < 4)) + { + scan_lines = 200; /* Low res text mode */ + } + else + { + switch (get_VGA_lines()) + { + case S200: + scan_lines = 200; + break; + case S350: + scan_lines = 350; + break; + case S400: + scan_lines = 400; + break; + default: + + /* Dodgy value in BIOS data area - don't do anything. */ + assert0(NO, "invalid VGA lines in BIOS data"); + return; + } + } + + /* Now work out the number of text lines on the screen. */ + text_lines = scan_lines / font_height; + + /* If the number of lines has changed, select a new mouse buffer. */ + if (text_lines != saved_text_lines) + SelectMouseBuffer(mode, text_lines); + + } /* if ((mode == 0x2) || (mode == 0x3) || (mode == 0x7)) */ +} + +/*************************************************************************** + * Function: * + * SelectMouseBuffer * + * * + * Description: * + * Selects the correct screen ratio for the video mode.at the * + * * + * Parameters: * + * mode - the video mode for which we are setting a screen buffer. * + * lines - for text modes: the number of character lines on the * + * screen, 0 denotes the default for this mode. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID SelectMouseBuffer(half_word mode, half_word lines) +{ + DWORD width, + height; + + + /* + ** When stdout is being redirected we must not set up the graphics + ** buffer for the mouse. Otherwise 32-bit progs like MORE crash + ** cos they ask console for the active console handle and get + ** confused. We get told by DOS Em. when stdout is being + ** redirected and do not set up the buffer. + ** Tim Jan 93. + */ + if( stdoutRedirected ) + return; + + /* Work out the screen resolution. */ + switch (mode & 0x7f) + { + case 0x0: + case 0x1: + width = 640; + height = 200; + break; + case 0x2: + case 0x3: + case 0x7: + switch (lines) + { + case 0: + case 25: + saved_text_lines = 25; + width = 640; + height = 200; + break; + case 43: + saved_text_lines = 43; + width = 640; + height = 344; + break; + case 50: + saved_text_lines = 50; + width = 640; + height = 400; + break; + default: + assert1(NO, "strange number of lines for text mode - %d", lines); + return; + } + break; + case 0x4: + case 0x5: + case 0x6: + case 0xd: + case 0xe: + width = 640; + height = 200; + break; + case 0xf: + case 0x10: + width = 640; + height = 350; + break; + case 0x11: + case 0x12: + width = 640; + height = 480; + break; + case 0x13: + width = 640; + height = 200; + break; + case 0x40: + width = 640; + height = 400; + break; + case 0x41: + case 0x42: + width = 1056; + height = 344; + break; + case 0x43: + width = 640; + height = 480; + break; + case 0x44: + width = 800; + height = 480; + break; + case 0x45: + width = 1056; + height = 392; + break; + case 0x60: + width = 752; + height = 408; + break; + case 0x61: + width = 720; + height = 536; + break; + case 0x62: + width = 800; + height = 600; + break; + case 0x63: + case 0x64: + case 0x65: + width = 1024; + height = 768; + break; + case 0x66: + width = 640; + height = 400; + break; + case 0x67: + width = 640; + height = 480; + break; + case 0x68: + width = 720; + height = 540; + break; + case 0x69: + width = 800; + height = 600; + break; + default: + + /* No change if we get an unknown mode. */ + assert1(NO, "unknown mode - %d", mode); + return; + } + + // + // Set the variables to let apps like Word and Works which call + // INT 33h AX = 26h to find out the size of the current virtual + // screen. + // Andy! + + VirtualX = (word)width; + VirtualY = (word)height; + + /* Save current dimensions. */ + mouse_buffer_width = width; + mouse_buffer_height = height; + +} +#endif /* X86GFX */ + +void host_enable_stream_io(void) +{ + sc.ScreenState = STREAM_IO; + host_stream_io_enabled = TRUE; + +} +void host_disable_stream_io(void) +{ + DWORD mode; + + if(!GetConsoleMode(sc.InputHandle, &mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + mode |= (ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + if(!SetConsoleMode(sc.InputHandle,mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + + + if(!GetConsoleMode(sc.OutputHandle, &mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + if(!stdoutRedirected) + { + mode &= ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT); + + if(!SetConsoleMode(sc.OutputHandle,mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + } + + ConsoleInit(); + (void)(*choose_display_mode)(); + /* + ** Copy the console buffer to the regen buffer. + ** Don't want to adjust the copy from top of console window, console + ** does it itself if we resize the window. Tim September 92. + */ + copyConsoleToRegen(0, 0, VGA_WIDTH, (SHORT)ConVGAHeight); + + /* + ** Tim September 92, adjust cursor position if console window size is + ** adjusted. + */ + ConsBufferInfo.dwCursorPosition.Y -= ConTopLine; + + /* Set up SoftPC's cursor. */ + setVDMCursorPosition((UTINY)StartupCharHeight, + &ConsBufferInfo.dwCursorPosition); + + if (sc.ScreenState == WINDOWED) + enableUpdates(); + + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + host_stream_io_enabled = FALSE; +} diff --git a/private/mvdm/softpc.new/host/src/nt_graph.c b/private/mvdm/softpc.new/host/src/nt_graph.c new file mode 100644 index 000000000..a0a56df31 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_graph.c @@ -0,0 +1,2314 @@ +#include <windows.h> +#include "host_def.h" +#include "insignia.h" + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + Name: nt_graph.c + Author: Dave Bartlett (based on module by John Shanly) + Derived From: X_graph.c + Created On: 10/5/1991 + Sccs ID: @(#)nt_graph.c 1.29 04/17/91 + Purpose: + This modules contain all Win32 specific functions required to + support HERC, CGA and EGA emulations. It is by definition + Win32 specific. It contains full support for the Host + Graphics Interface (HGI). + + This module handles all graphics output to the screen. + + (c)Copyright Insignia Solutions Ltd., 1990. All rights reserved. + + Modifications: + Tim August 92. nt_set_paint_routine() no longer calls TextToGraphics() + during a full-screen to windowed transition. + Tim September 92. New function resizeWindow(), called from textResize() + for resizing the console window. +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#ifdef X86GFX +#include <ntddvdeo.h> +#endif +#include <sys\types.h> + +#include "xt.h" +#include CpuH +#include "sas.h" +#include "ica.h" +#include "gvi.h" +#include "cga.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "egagraph.h" +#include "egacpu.h" +#include "egaports.h" +#include "egamode.h" +#include "host.h" +#include "host_rrr.h" +#include "error.h" +#include "config.h" /* For definition of HERC, CGA, EGA, VGA */ +#include "idetect.h" +#include "video.h" +#include "ckmalloc.h" +#include "conapi.h" + +#include "nt_graph.h" +#include "nt_cga.h" +#include "nt_ega.h" +#include "nt_event.h" +#include "nt_mouse.h" +#include "ntcheese.h" +#include "nt_uis.h" +#include "nt_fulsc.h" +#include "nt_det.h" + +#include <stdio.h> +#include <stdlib.h> +#include <malloc.h> +#include "trace.h" +#include "debug.h" + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: IMPORTS */ + +/* Globals used in various functions to synchronise the display */ + +#ifdef EGG +extern int ega_int_enable; +#endif + +extern byte *video_copy; + +static int flush_count = 0; /*count of graphic ticks since last flush*/ + +// DIB_PAL_INDICES shouldn't be used, use CreateDIBSECTION to get better +// performance characteristics. + +#define DIB_PAL_INDICES 2 + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: EXPORTS */ + +SCREEN_DESCRIPTION sc; + +#ifdef BIGWIN +int horiz_lut[256]; +#endif +int host_screen_scale; +int host_display_depth = 8; +int top_plane; +char *DIBData; +PBITMAPINFO MonoDIB; +PBITMAPINFO CGADIB; +PBITMAPINFO EGADIB; +PBITMAPINFO VGADIB; + +void (*paint_screen)(); +BOOL FunnyPaintMode; + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Paint functions */ + +static PAINTFUNCS std_mono_paint_funcs = +{ + nt_text, + nt_cga_mono_graph_std, + nt_cga_mono_graph_std, + nt_text, + nt_ega_mono_lo_graph_std, + nt_ega_mono_med_graph_std, + nt_ega_mono_hi_graph_std, + nt_vga_mono_graph_std, + nt_vga_mono_med_graph_std, + nt_vga_mono_hi_graph_std, +#ifdef V7VGA + nt_v7vga_mono_hi_graph_std, +#endif /* V7VGA */ +}; + +static PAINTFUNCS big_mono_paint_funcs = +{ + nt_text, + nt_cga_mono_graph_big, + nt_cga_mono_graph_big, + nt_text, + nt_ega_mono_lo_graph_big, + nt_ega_mono_med_graph_big, + nt_ega_mono_hi_graph_big, + nt_vga_mono_graph_big, + nt_vga_mono_med_graph_big, + nt_vga_mono_hi_graph_big, +#ifdef V7VGA + nt_v7vga_mono_hi_graph_big, +#endif /* V7VGA */ +}; + +static PAINTFUNCS huge_mono_paint_funcs = +{ + nt_text, + nt_cga_mono_graph_huge, + nt_cga_mono_graph_huge, + nt_text, + nt_ega_mono_lo_graph_huge, + nt_ega_mono_med_graph_huge, + nt_ega_mono_hi_graph_huge, + nt_vga_mono_graph_huge, + nt_vga_mono_med_graph_huge, + nt_vga_mono_hi_graph_huge, +#ifdef V7VGA + nt_v7vga_mono_hi_graph_huge, +#endif /* V7VGA */ +}; + +static PAINTFUNCS std_colour_paint_funcs = +{ + nt_text, + nt_cga_colour_med_graph_std, + nt_cga_colour_hi_graph_std, + nt_text, + nt_ega_lo_graph_std, + nt_ega_med_graph_std, + nt_ega_hi_graph_std, + nt_vga_graph_std, + nt_vga_med_graph_std, + nt_vga_hi_graph_std, +#ifdef V7VGA + nt_v7vga_hi_graph_std, +#endif /* V7VGA */ +}; + +static PAINTFUNCS big_colour_paint_funcs = +{ + nt_text, + nt_cga_colour_med_graph_big, + nt_cga_colour_hi_graph_big, + nt_text, + nt_ega_lo_graph_big, + nt_ega_med_graph_big, + nt_ega_hi_graph_big, + nt_vga_graph_big, + nt_vga_med_graph_big, + nt_vga_hi_graph_big, +#ifdef V7VGA + nt_v7vga_hi_graph_big, +#endif /* V7VGA */ +}; + +static PAINTFUNCS huge_colour_paint_funcs = +{ + nt_text, + nt_cga_colour_med_graph_huge, + nt_cga_colour_hi_graph_huge, + nt_text, + nt_ega_lo_graph_huge, + nt_ega_med_graph_huge, + nt_ega_hi_graph_huge, + nt_vga_graph_huge, + nt_vga_med_graph_huge, + nt_vga_hi_graph_huge, +#ifdef V7VGA + nt_v7vga_hi_graph_huge, +#endif /* V7VGA */ +}; + +#ifdef MONITOR +static PAINTFUNCS std_frozen_paint_funcs = +{ + nt_dummy_frozen, + nt_cga_med_frozen_std, + nt_cga_hi_frozen_std, + nt_dummy_frozen, + nt_ega_lo_frozen_std, + nt_ega_med_frozen_std, + nt_ega_hi_frozen_std, + nt_vga_frozen_std, + nt_vga_med_frozen_std, + nt_vga_hi_frozen_std, +#ifdef V7VGA + nt_dummy_frozen, +#endif /* V7VGA */ +}; + +static PAINTFUNCS big_frozen_paint_funcs = +{ + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, +#ifdef V7VGA + nt_dummy_frozen, +#endif /* V7VGA */ +}; + +static PAINTFUNCS huge_frozen_paint_funcs = +{ + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, + nt_dummy_frozen, +#ifdef V7VGA + nt_dummy_frozen, +#endif /* V7VGA */ +}; +#endif /* MONITOR */ + +static INITFUNCS mono_init_funcs = +{ + nt_init_text, + nt_init_cga_mono_graph, + nt_init_cga_mono_graph, + nt_init_text, + nt_init_ega_mono_lo_graph, + nt_init_ega_med_graph, + nt_init_ega_hi_graph, + nt_init_vga_hi_graph, +}; + +static INITFUNCS colour_init_funcs = +{ + nt_init_text, + nt_init_cga_colour_med_graph, + nt_init_cga_colour_hi_graph, + nt_init_text, + nt_init_ega_lo_graph, + nt_init_ega_med_graph, + nt_init_ega_hi_graph, + nt_init_vga_hi_graph, +}; + +#ifdef MONITOR +static INITFUNCS frozen_init_funcs = +{ + nt_init_text, + nt_init_cga_colour_med_graph, + nt_init_cga_colour_hi_graph, + nt_init_text, + nt_init_ega_lo_graph, + nt_init_ega_med_graph, + nt_init_ega_hi_graph, + nt_init_vga_hi_graph, +}; +#endif /* MONITOR */ + +/*::::::::::::::::::::::::::::::::::::::::::::::: Adaptor function protocol */ + +void nt_init_screen (void); +void nt_init_adaptor (int, int); +void nt_change_mode (void); +void nt_set_screen_scale(int); +void nt_set_palette(PC_palette *, int); +void nt_set_border_colour(int); +void nt_clear_screen (void); +void nt_flush_screen (void); +void nt_mark_screen_refresh (void); +void nt_graphics_tick (void); +void nt_start_update (void); +void nt_end_update (void); +void nt_paint_cursor IPT3(int, cursor_x, int, cursor_y, half_word, attr); + +void nt_set_paint_routine(DISPLAY_MODE, int); +void nt_change_plane_mask(int); +void nt_update_fonts (void); +void nt_select_fonts(int, int); +void nt_free_font(int); + +void nt_mode_select_changed(int); +void nt_color_select_changed(int); +void nt_screen_address_changed(int, int); +void nt_cursor_size_changed(int, int); +void nt_scroll_complete (void); +void make_cursor_change(void); + +boolean nt_scroll_up(int, int, int, int, int, int); +boolean nt_scroll_down(int, int, int, int, int, int); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static PAINTFUNCS *nt_paint_funcs; /* Function ptrs for paint functions */ +static INITFUNCS *nt_init_funcs; /* Function ptrs for init functions */ + +VIDEOFUNCS nt_video_funcs = +{ + nt_init_screen, + nt_init_adaptor, + nt_change_mode, + nt_set_screen_scale, + nt_set_palette, + nt_set_border_colour, + nt_clear_screen, + nt_flush_screen, + nt_mark_screen_refresh, + nt_graphics_tick, + nt_start_update, + nt_end_update, + nt_scroll_up, + nt_scroll_down, + nt_paint_cursor, + nt_set_paint_routine, + nt_change_plane_mask, + nt_update_fonts, + nt_select_fonts, + nt_free_font, + nt_mode_select_changed, + nt_color_select_changed, + nt_screen_address_changed, + nt_cursor_size_changed, + nt_scroll_complete +}; + +static int current_char_height = 0; +static int current_height; /* Use to avoid redundant resizing */ +static int current_width; /* Use to avoid redundant resizing */ +static int current_bits_per_pixel; +static int current_mode_type = TEXT; +static int current_mode; +static int current_scale; +static int palette_size; /* Size of PC palette */ +static PC_palette *the_palette; /* Pointer to PC palette structure */ +static int update_vlt = FALSE; /* TRUE when new one needed */ +static int host_plane_mask = 0xf; +static int plane_masks[4]; + +#ifdef BIGWIN + +/* + * * tiny_lut[] is the building block of all the strecthing fuctions. * It + * performs a two to three bit mapping. * The four entries are three bits + * wide. The outside two bits in * each entry are the original bits, the + * inside bit is the new bit. * There are two methods to create the new bit: * + * 1) Logical Op upon the two old bits eg. OR, AND * 2) Copy one of the bits + * eg. New bit will be a copy of the left bit. * static short tiny_lut[4] = { + * 0, 3, 6, 7 }; This is an OR * static short tiny_lut[4] = { 0, 1, 6, 7 }; + * This is a left bit copy * Potential advantage of copy instead of logical + * op is that there is no * bias towards white or black versions of the same + * image. * eg. when a menu entry is highlighted by inversion. * + * + * 00 -> 000 * 01 -> 001 * 10 -> 110 * 11 -> 111 + */ + +/* favours black if 0, 1, 4, 7, or white if 0, 3, 6, 7 */ +static short tiny_lut[4] = +{ + 0, 1, 6, 7 +}; + +/* + * dubble_up is used for simple byte doubling for x2 size windows + */ +static word dubble_up[] = { + 0x0000, 0x0003, 0x000c, 0x000f, 0x0030, 0x0033, 0x003c, 0x003f, 0x00c0, + 0x00c3, 0x00cc, 0x00cf, 0x00f0, 0x00f3, 0x00fc, 0x00ff, 0x0300, 0x0303, + 0x030c, 0x030f, 0x0330, 0x0333, 0x033c, 0x033f, 0x03c0, 0x03c3, 0x03cc, + 0x03cf, 0x03f0, 0x03f3, 0x03fc, 0x03ff, 0x0c00, 0x0c03, 0x0c0c, 0x0c0f, + 0x0c30, 0x0c33, 0x0c3c, 0x0c3f, 0x0cc0, 0x0cc3, 0x0ccc, 0x0ccf, 0x0cf0, + 0x0cf3, 0x0cfc, 0x0cff, 0x0f00, 0x0f03, 0x0f0c, 0x0f0f, 0x0f30, 0x0f33, + 0x0f3c, 0x0f3f, 0x0fc0, 0x0fc3, 0x0fcc, 0x0fcf, 0x0ff0, 0x0ff3, 0x0ffc, + 0x0fff, 0x3000, 0x3003, 0x300c, 0x300f, 0x3030, 0x3033, 0x303c, 0x303f, + 0x30c0, 0x30c3, 0x30cc, 0x30cf, 0x30f0, 0x30f3, 0x30fc, 0x30ff, 0x3300, + 0x3303, 0x330c, 0x330f, 0x3330, 0x3333, 0x333c, 0x333f, 0x33c0, 0x33c3, + 0x33cc, 0x33cf, 0x33f0, 0x33f3, 0x33fc, 0x33ff, 0x3c00, 0x3c03, 0x3c0c, + 0x3c0f, 0x3c30, 0x3c33, 0x3c3c, 0x3c3f, 0x3cc0, 0x3cc3, 0x3ccc, 0x3ccf, + 0x3cf0, 0x3cf3, 0x3cfc, 0x3cff, 0x3f00, 0x3f03, 0x3f0c, 0x3f0f, 0x3f30, + 0x3f33, 0x3f3c, 0x3f3f, 0x3fc0, 0x3fc3, 0x3fcc, 0x3fcf, 0x3ff0, 0x3ff3, + 0x3ffc, 0x3fff, 0xc000, 0xc003, 0xc00c, 0xc00f, 0xc030, 0xc033, 0xc03c, + 0xc03f, 0xc0c0, 0xc0c3, 0xc0cc, 0xc0cf, 0xc0f0, 0xc0f3, 0xc0fc, 0xc0ff, + 0xc300, 0xc303, 0xc30c, 0xc30f, 0xc330, 0xc333, 0xc33c, 0xc33f, 0xc3c0, + 0xc3c3, 0xc3cc, 0xc3cf, 0xc3f0, 0xc3f3, 0xc3fc, 0xc3ff, 0xcc00, 0xcc03, + 0xcc0c, 0xcc0f, 0xcc30, 0xcc33, 0xcc3c, 0xcc3f, 0xccc0, 0xccc3, 0xcccc, + 0xcccf, 0xccf0, 0xccf3, 0xccfc, 0xccff, 0xcf00, 0xcf03, 0xcf0c, 0xcf0f, + 0xcf30, 0xcf33, 0xcf3c, 0xcf3f, 0xcfc0, 0xcfc3, 0xcfcc, 0xcfcf, 0xcff0, + 0xcff3, 0xcffc, 0xcfff, 0xf000, 0xf003, 0xf00c, 0xf00f, 0xf030, 0xf033, + 0xf03c, 0xf03f, 0xf0c0, 0xf0c3, 0xf0cc, 0xf0cf, 0xf0f0, 0xf0f3, 0xf0fc, + 0xf0ff, 0xf300, 0xf303, 0xf30c, 0xf30f, 0xf330, 0xf333, 0xf33c, 0xf33f, + 0xf3c0, 0xf3c3, 0xf3cc, 0xf3cf, 0xf3f0, 0xf3f3, 0xf3fc, 0xf3ff, 0xfc00, + 0xfc03, 0xfc0c, 0xfc0f, 0xfc30, 0xfc33, 0xfc3c, 0xfc3f, 0xfcc0, 0xfcc3, + 0xfccc, 0xfccf, 0xfcf0, 0xfcf3, 0xfcfc, 0xfcff, 0xff00, 0xff03, 0xff0c, + 0xff0f, 0xff30, 0xff33, 0xff3c, 0xff3f, 0xffc0, 0xffc3, 0xffcc, 0xffcf, + 0xfff0, 0xfff3, 0xfffc, 0xffff +}; +#endif /* BIGWIN */ + +/*:::::::::: Temporary colour table to make colours work :::::::::::::::*/ +extern BYTE Red[]; +extern BYTE Green[]; +extern BYTE Blue[]; + +GLOBAL BOOL host_stream_io_enabled = FALSE; + +GLOBAL COLOURTAB defaultColours = + { + DEFAULT_NUM_COLOURS, + Red, + Green, + Blue, + }; + +BYTE Mono[] = { 0, 0xff }; + +GLOBAL COLOURTAB monoColours = + { + MONO_COLOURS, + Mono, + Mono, + Mono, + }; + +/* + * Bit masks for attribute bytes + */ + +#define BOLD 0x08 /* Bold bit */ + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::: Useful Constants */ + +#define MOUSE_DELAY 2 +#define TICKS_PER_FLUSH 2 /* PC ticks per screen flush */ + +/*:::::::::::::::::::::::::::::::::::::::::: Not supporting v7vga mode, yet */ + +#undef is_v7vga_mode +#define is_v7vga_mode(x) (FALSE) + +static int mode_change_now; +static int ega_tick_delay; +static BOOL CursorResizeNeeded = FALSE; + +/*:::::::::::: Definition of local functions declared later in file ????????*/ +void set_screen_sizes(); +void check_win_size(); +void select_paint_routines(); +void dummy_paint_screen(); +#ifdef BIGWIN +void init_lut(); +#endif +void prepare_surface(); + + + + +/* + * ================================================================ + * Functions supporting the Host Graphics Interface (HGI) + * ================================================================ + */ + +/* +***************************************************************************** +** closeGraphicsBuffer() +***************************************************************************** +** Centralised place to close (and destroy) graphics buffer. For X86 and JAZZ +** Tim October 92. +** +** sc.ScreenBufHandle is handle to the graphics buffer +** sc.OutputHandle is handle to the text buffer +** +** Important to set the successfully closed handle to NULL. +** Safety first, set the active handle to sc.OutputHandle before attempting +** to close the graphics buffer handle. +** +** Small change: only do this if sc.ScreenBufHandle is set, otherwise bad +** things happen. Screen flashes when we suspend in full-screen and during +** a transition to full-screen in text mode, whatever is on screen gets +** written to B800 - not a good idea if page 2 is active (This happens +** in Brief). Tim and DAB Jan 93. +*/ +GLOBAL VOID closeGraphicsBuffer IFN0() +{ + if( sc.ScreenBufHandle != (HANDLE)0 ){ + + MouseDetachMenuItem(TRUE); + + if( !SetConsoleActiveScreenBuffer( sc.OutputHandle ) ){ + assert2( NO, "VDM: SCASB() failed:%#x H=%#x", + GetLastError(), sc.OutputHandle ); + } + + /* + * Cleanup ALL handles associated with screen buffer + * 01-Mar-1993 Jonle + */ + CloseHandle(sc.ScreenBufHandle); + sc.ScreenBufHandle = (HANDLE)0; + sc.ColPalette = (HPALETTE)0; + + /* + * Point to the current output handle. + */ + sc.ActiveOutputBufferHandle = sc.OutputHandle; + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + +#ifndef MONITOR + // + // Turn the pointer back on when going from graphics + // to text mode since the selected buffer has changed + // + + MouseDisplay(); +#endif // MONITOR + + CloseHandle(sc.ConsoleBufInfo.hMutex); + sc.ConsoleBufInfo.hMutex = 0; +#ifdef X86GFX + + /* + * Make sure a buffer is selected next time SelectMouseBuffer + * is called. + */ + mouse_buffer_width = 0; + mouse_buffer_height = 0; +#endif /* X86GFX */ + } +} /* end of closeGraphicsBuffer() */ + +GLOBAL void resetWindowParams() +{ + /* + * Reset saved video params + */ + current_height = current_width = 0; + current_char_height = 0; + current_mode_type = TEXT; + current_bits_per_pixel = 0; + current_scale = 0; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Initialise screen :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_screen(void) +{ + static int med_res_swapped = FALSE; + static boolean already_called = FALSE; + +#ifdef X86GFX + sc.Registered = FALSE; +#endif + sub_note_trace0(ALL_ADAPT_VERBOSE, "nt_init_screen\n"); + + /* If an error occurs before the user interface has been initialised then + host_error makes a call to nt_init_screen. Thus a check is made here to + see if the user interface has already been initialised. If it has then + this function should simply return. */ + + if(already_called) return; + + already_called = TRUE; + +#ifdef BIGWIN + /* set up the look-up-table for fast horizontal stretching */ + init_lut(); +#endif + + /*:::::::::::::::::::::::::::::::::::::::::: Allocate video copy buffer */ + +#ifdef MONITOR + if(!video_copy) video_copy = (byte *) host_malloc(0x8000); +#else + if(!video_copy) video_copy = (byte *) host_malloc(0x20000); +#endif + + /*::::::::::::::::::::::::::::::::: Allocate DAC and EGA planes buffers */ + + if(!EGA_planes) EGA_planes = (byte *) host_malloc(4*EGA_PLANE_SIZE); + if(!DAC) DAC = (PC_palette *) host_malloc(sizeof(PC_palette) * VGA_DAC_SIZE); + + if (video_copy == NULL || EGA_planes == NULL || DAC == NULL) + host_error(EG_MALLOC_FAILURE, ERR_QUIT, ""); + + /* Set current screen height to prevent the window changing shape between + init_screen and init_adaptor */ + + video_adapter = (half_word) config_inquire(C_GFX_ADAPTER, NULL); + switch (video_adapter) + { + case CGA: + current_height = CGA_WIN_HEIGHT; current_width = CGA_WIN_WIDTH; + break; + + case EGA: + current_height = EGA_WIN_HEIGHT; current_width = EGA_WIN_WIDTH; + break; + } + + /*::::::::::::::::: Setup the screen dimensions for the initial adaptor */ + + host_set_screen_scale((SHORT) config_inquire(C_WIN_SIZE, NULL)); + set_screen_sizes(video_adapter); + + /*:::: Set pixel values to be used for FG and BG (mainly in mono modes) */ + + sc.PCForeground = RGB(255,255,255); /* White RGB */ + sc.PCBackground = RGB(0,0,0); /* Black RGB */ + + /* Choose the routines appropriate for the monitor and window size. */ + select_paint_routines(); +} + +#ifdef MONITOR +/* The mouse calls this func when it sees a mode change. If we're windowed + * we pass it off to the softpc bios (who may want to switch to fullscreen). + * If we're fullscreen we do nothing as the native bios will take care of + * everything. + */ +void host_call_bios_mode_change(void) +{ + extern void ega_video_io(); + half_word mode; + + if (sc.ScreenState == WINDOWED) + { + ega_video_io(); + } + else + { + + /* + * We have a fullscreen mode change so we need to change the mouse + * buffer so that we get mouse coordinates of the correct resolution. + */ + mode = getAL(); + SelectMouseBuffer(mode, 0); + } +} +#endif /* MONITOR */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Initialise adaptor ::::::::::::::::::::::::::::*/ + +void nt_init_adaptor(int adaptor, int height) +{ + sub_note_trace2(ALL_ADAPT_VERBOSE, + "nt_init_adaptor adapt=%d height=%d\n", adaptor, height); + + /*Avoid delaying mode changes,otherwise update may use old paint routines*/ + + if((adaptor == EGA) || (adaptor == VGA)) + mode_change_now = ega_tick_delay = 0; + + // Lose for console integration + // set_screen_sizes(adaptor); + // check_win_size(height); + // prepare_surface(); + // nt_change_mode(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::: Called at every mode change to initialise fonts etc ::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_change_mode(void) +{ + /*::::::::::::::::::::::::::::::::::::: Display current postion in code */ + + sub_note_trace0(ALL_ADAPT_VERBOSE, "nt_change_mode"); + + /*:::::::::::::::::::: Setup update vectors and initialise paint system */ + + switch(video_adapter) + { + /*::::::::::::::::::::::::::::::::::::::::::::::: CGA mode selected */ + + case CGA: // Adapter is always VGA on NT + break; + + /*::::::::::::::::::::::::::::::::::::::: EGA or VGA modes selected */ + + case EGA: case VGA: + break; + + /*::::::::::::::::::::::::::::::::::::::::::: Unknown viseo adaptor */ + + default: + sub_note_trace0(ALL_ADAPT_VERBOSE,"**** Unknown video adaptor ****"); + break; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::: Clear screen :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_clear_screen(void) +{ + CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; + COORD coord; + DWORD nCharWritten; + IMPORT int soft_reset; + + if ((! ConsoleInitialised) || (! soft_reset)) // ignore startup stuff + return; + + if (ConsoleNoUpdates) + return; + + sub_note_trace0(ALL_ADAPT_VERBOSE, "nt_clear_screen"); + + if(sc.ScreenBufHandle) return; + +#ifndef X86GFX + if (sc.ScreenState == FULLSCREEN) // don't want sudden screen clears + return; +#endif + + /*::::::::::::::::::::::::::::: Get information on current screen size */ + + GetConsoleScreenBufferInfo(sc.OutputHandle,&ScreenInfo); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::: Clear characters */ + + coord.X = coord.Y = 0; + FillConsoleOutputCharacter(sc.OutputHandle, ' ', + ScreenInfo.dwSize.X * ScreenInfo.dwSize.Y, + coord,&nCharWritten); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::: Clear Attributes */ + + coord.X = coord.Y = 0; + FillConsoleOutputAttribute(sc.OutputHandle, (WORD) sc.PCBackground, + ScreenInfo.dwSize.X * ScreenInfo.dwSize.Y, + coord,&nCharWritten); +#ifdef MONITOR + /* + ** Called during a mode change... + ** Trash video copy so future updates will know what has changed. + ** Alternatively mon_text_update() could listen to dirty_flag. + */ + memfill( 0xff, &video_copy[ 0 ], &video_copy[ 0x7fff ] ); /* Tim Oct 92 */ +#endif +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::: Flush screen :::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_flush_screen(void) +{ + sub_note_trace0(ALL_ADAPT_VERBOSE, "nt_flush_screen"); + + if (ConsoleInitialised == TRUE && ConsoleNoUpdates == FALSE && + !get_mode_change_required()) +#ifdef X86GFX + if (sc.ScreenState == WINDOWED) +#endif + (void)(*update_alg.calc_update)(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Mark screen for refresh :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_mark_screen_refresh(void) +{ + sub_note_trace0(ALL_ADAPT_VERBOSE, "nt_mark_screen_refresh"); + + screen_refresh_required(); + update_vlt = TRUE; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Handle graphics ticks ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_graphics_tick(void) +{ + + if (sc.ScreenState == STREAM_IO) { + if (++flush_count == TICKS_PER_FLUSH){ + stream_io_update(); + flush_count = 0; + } + return; + } + +#ifdef EGG + if((video_adapter == EGA) || (video_adapter == VGA)) + { + /* two timer ticks since mode_change_required became true ? + (really need same stuff for CGA, but not done yet) + Now just delay screen update, & only if display REALLY changed */ + + /* + ** When VGA registers get hit during a mode change, postpone + ** the call to *choose_display_mode() by EGA_TICK_DELAY ticks. + ** This will delay window resizing and eliminate possibility + ** of doing it more than once per mode change. Tim Jan 93. + */ + + /*Has mode_change_required been set (implying EGA regs have changed)*/ + if (mode_change_now) { + if (--mode_change_now == 0) { + (void)(*choose_display_mode)(); + // must do this after video mode has been selected + // otherwise, the mouse code can come in and update the + // screen. See nt_flush_screen + set_mode_change_required(FALSE); + } + } + else if (get_mode_change_required()) { + mode_change_now = EGA_TICK_DELAY - 1; + /* Delay mouse input and flush all pending mouse events. */ + DelayMouseEvents(MOUSE_DELAY); + } + else + { + /*................ Only update if a mode change is not imminent */ + + if(++flush_count == TICKS_PER_FLUSH) + { + + if(update_vlt || get_palette_change_required()) + set_the_vlt(); + + if (ConsoleInitialised == TRUE && ConsoleNoUpdates == FALSE) +#ifdef X86GFX + if (sc.ScreenState == WINDOWED) +#endif + (void)(*update_alg.calc_update)(); + + ega_tick_delay = EGA_TICK_DELAY; + + /* batch cursor changes as some naffola apps (Word) change + * cursor around every char!! + */ + if (CursorResizeNeeded) + make_cursor_change(); + + flush_count = 0; + } + } + } + else +#endif /* EGG */ + { + /*:::::::::: Update the screen as required for mda and cga and herc */ + + if(++flush_count == TICKS_PER_FLUSH) + { + if(update_vlt) set_the_vlt(); + + if (ConsoleInitialised == TRUE && ConsoleNoUpdates == FALSE) +#ifdef X86GFX + if (sc.ScreenState == WINDOWED) +#endif + (void)(*update_alg.calc_update)(); + + flush_count = 0; + } + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Start screen update ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_start_update(void) +{ + IDLE_video(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: End screen update ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_end_update(void) { } + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::: Scroll screen up :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +boolean nt_scroll_up(int tlx, int tly, int brx, int bry, int amount, int col) +{ + CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; + COORD dwDestinationOrigin; /* Location of rectangle */ + SMALL_RECT ScrollRectangle; /* Rectangle to scroll */ + CHAR_INFO Fill; /* Fill exposed region with */ + + return(FALSE); + + /*::::::::::::::::::::::::::::::::: Tell the outside world where we are */ + + sub_note_trace6(ALL_ADAPT_VERBOSE, + "nt_scroll_up tlx=%d tly=%d brx=%d bry=%d amount=%d col=%d\n", + tlx, tly, brx, bry, amount, col); + + if(sc.ScreenBufHandle || sc.ModeType == GRAPHICS) + return(FALSE); //Screen buffer undefined or in graphics mode + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +#ifdef BIGWIN + tlx = SCALE(tlx); + tly = SCALE(tly); + brx = brx & 1 ? SCALE(brx + 1) - 1 : SCALE(brx); + bry = bry & 1 ? SCALE(bry + 1) - 1 : SCALE(bry); + + /* odd numbers don't multiply by 1.5 very accurately */ + amount = SCALE(amount); +#endif + + + /* is this a scroll or just an area fill? */ + if (bry - tly - amount + 1 == 0) + { + //DbgPrint("F"); + return(FALSE); // its just a fill HACK - should do this with host fill + } + + /*:::::::::::::::::::::::::::::::::::::: Get Console screen information */ + + GetConsoleScreenBufferInfo(sc.OutputHandle, &ScreenInfo); + + /*::::::::::::::::::::::::::::::::::::::: Calculate rectangle to scroll */ + + ScrollRectangle.Top = (tly + amount) / get_char_height(); + ScrollRectangle.Left = tlx / get_pix_char_width(); + + ScrollRectangle.Bottom = bry / get_char_height(); + ScrollRectangle.Right = brx / get_pix_char_width(); + + /*::::::::::::::::::::::::::::::::::::: Calculate destination rectangle */ + + dwDestinationOrigin.Y = tly / get_char_height(); + dwDestinationOrigin.X = ScrollRectangle.Left; + + /*::::: Setup fill character information for area exposed by the scroll */ + + Fill.Char.AsciiChar = ' '; + Fill.Attributes = col << 4; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Scroll screen */ + + //DbgPrint("."); + ScrollConsoleScreenBuffer(sc.OutputHandle, &ScrollRectangle, + NULL, dwDestinationOrigin, &Fill); + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Fill in exposed area */ + + return(TRUE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Scroll screen down :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +boolean nt_scroll_down(int tlx,int tly,int brx,int bry,int amount,int col) +{ + CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; + COORD dwDestinationOrigin; /* Location of rectangle */ + SMALL_RECT ScrollRectangle; /* Rectangle to scroll */ + CHAR_INFO Fill; /* Fill exposed region with */ + + /*::::::::::::::::::::::::::::::::: Tell the outside world where we are */ + + sub_note_trace6(ALL_ADAPT_VERBOSE, + "nt_scroll_down tlx=%d tly=%d brx=%d bry=%d amount=%d col=%d\n", + tlx, tly, brx, bry, amount, col); + + return(FALSE); + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + if(sc.ScreenBufHandle) return(FALSE); + +#ifdef BIGWIN + tlx = SCALE(tlx); + tly = SCALE(tly); + brx = brx & 1 ? SCALE(brx + 1) - 1 : SCALE(brx); + bry = bry & 1 ? SCALE(bry + 1) - 1 : SCALE(bry); + + /* odd numbers don't multiply by 1.5 very accurately */ + amount = SCALE(amount); +#endif + if (sc.ModeType == GRAPHICS) + return(FALSE); // don't think console can scroll graphics + + /* is this a scroll or just an area fill? */ + if (bry - tly - amount + 1 == 0) { + return(FALSE); // its just a fill HACK - should do this with host fill + } + + /*:::::::::::::::::::::::::::::::::::::: Get Console screen information */ + + GetConsoleScreenBufferInfo(sc.OutputHandle, &ScreenInfo); + + /*::::::::::::::::::::::::::::::::::::::: Calculate rectangle to scroll */ + + ScrollRectangle.Top = tly / get_char_height(); + ScrollRectangle.Left = tlx / get_pix_char_width(); + + ScrollRectangle.Bottom = (bry - amount) / get_char_height(); + ScrollRectangle.Right = brx / get_pix_char_width(); + + /*::::::::::::::::::::::::::::::::::::: Calculate destination rectangle */ + + dwDestinationOrigin.Y = ScrollRectangle.Top + (amount / get_char_height()); + dwDestinationOrigin.X = ScrollRectangle.Left; + + /*::::: Setup fill character information for area exposed by the scroll */ + + Fill.Char.AsciiChar = ' '; + Fill.Attributes = col << 4; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Scroll screen */ + + ScrollConsoleScreenBuffer(sc.OutputHandle, &ScrollRectangle, + NULL, dwDestinationOrigin, &Fill); + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Fill in exposed area */ + + return(TRUE); + +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Paint cursor :::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_paint_cursor IFN3(int, cursor_x, int, cursor_y, half_word, attr) +{ + COORD CursorPos; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::: Guess where we are */ + + sub_note_trace3(ALL_ADAPT_VERBOSE, "nt_paint_cursor x=%d, y=%d, attr=%d\n", + cursor_x, cursor_y, attr); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Update cursor */ + + if(is_cursor_visible() && (get_screen_height() > cursor_y)) + { + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Draw cursor */ + + if(get_cursor_height() > 0) + { + /*...................................... Set new cursor postion */ + + CursorPos.X = cursor_x; CursorPos.Y = cursor_y; + SetConsoleCursorPosition(sc.OutputHandle,CursorPos); + } + } +} + +void nt_cursor_size_changed(int lo, int hi) +{ + UNREFERENCED_FORMAL_PARAMETER(lo); + UNREFERENCED_FORMAL_PARAMETER(hi); + CursorResizeNeeded = TRUE; +} + +void make_cursor_change(void) +{ + CONSOLE_CURSOR_INFO CursorInfo; + CONSOLE_FONT_INFO font; + COORD fontsize; + + SAVED DWORD CurrentCursorSize = (DWORD)-1; + SAVED BOOL CurNowOff = FALSE; + + if(sc.ScreenState == FULLSCREEN) return; + + CursorResizeNeeded = FALSE; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Update cursor */ + + if(is_cursor_visible()) + { + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Draw cursor */ + + if(get_cursor_height() > 0) + { + /*...........................................Change cursor size */ + + if(get_cursor_height()) + { + /* value has to be percentage of block filled */ + CursorInfo.dwSize = (get_cursor_height() * 100)/get_char_height(); + /* %age may be too small on smaller fonts, check size */ + fontsize.X = fontsize.Y = 0; + + /* get font index */ + if (GetCurrentConsoleFont(sc.OutputHandle, TRUE, &font) == FALSE) + CursorInfo.dwSize = 20; /* min 20% */ + else + { + fontsize = GetConsoleFontSize(sc.OutputHandle, font.nFont); + if (fontsize.Y != 0) /* what's the error return???? */ + { + if(((WORD)(100 / fontsize.Y)) >= CursorInfo.dwSize) + CursorInfo.dwSize = (DWORD) (100/fontsize.Y + 1); + } + else + CursorInfo.dwSize = (DWORD)20; /* min 20% */ + } + + if(CurrentCursorSize != CursorInfo.dwSize || CurNowOff) + { + CurrentCursorSize = CursorInfo.dwSize; + CurNowOff = FALSE; + CursorInfo.bVisible = TRUE; + SetConsoleCursorInfo(sc.OutputHandle,&CursorInfo); + } + } + } + } + else /* Turn cursor image off */ + { + if (CurNowOff == FALSE) + { + CursorInfo.dwSize = 1; + CursorInfo.bVisible = FALSE; + SetConsoleCursorInfo(sc.OutputHandle,&CursorInfo); + CurNowOff = TRUE; + } + } +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::: Set up the appropriate paint routine :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_set_paint_routine(DISPLAY_MODE mode, int height) +{ + int oldModeType; + + /* Tracing message. */ + sub_note_trace2(ALL_ADAPT_VERBOSE, "nt_set_paint_routine mode=%d height=%d", mode, height); + + /* Save old mode type for checking for text -> graphics transition. */ + oldModeType = sc.ModeType; + + /* For freezing. */ + FunnyPaintMode = FALSE; + + /* Set up paint vectors. */ + switch((int) mode) + { + + /* CGA modes (40 columns). */ + case TEXT_40_FUN: + assert1(NO,"Funny text mode selected %s",get_mode_string(mode)); + FunnyPaintMode = TRUE; + case CGA_TEXT_40_SP: + case CGA_TEXT_40_SP_WR: + case CGA_TEXT_40: + case CGA_TEXT_40_WR: + sc.ModeType = TEXT; + paint_screen = nt_paint_funcs->cga_text; + (*nt_init_funcs->cga_text) (); + break; + + /* CGA modes (80 columns). */ + case TEXT_80_FUN: + assert1(NO,"Funny text mode selected %s",get_mode_string(mode)); + FunnyPaintMode = TRUE; + case CGA_TEXT_80_SP: + case CGA_TEXT_80_SP_WR: + case CGA_TEXT_80: + case CGA_TEXT_80_WR: + sc.ModeType = TEXT; + paint_screen = nt_paint_funcs->cga_text; + (*nt_init_funcs->cga_text) (); + break; + + /* CGA modes (graphics). */ + case CGA_MED_FUN: + assert1(NO,"Funny graphics mode %s",get_mode_string(mode)); + FunnyPaintMode = TRUE; + case CGA_MED: + sc.ModeType = GRAPHICS; + paint_screen = nt_paint_funcs->cga_med_graph; + (*nt_init_funcs->cga_med_graph)(); + break; + + case CGA_HI_FUN: + assert1(NO,"Funny graphics mode %s",get_mode_string(mode)); + FunnyPaintMode = TRUE; + case CGA_HI: + sc.ModeType = GRAPHICS; + paint_screen = nt_paint_funcs->cga_hi_graph; + (*nt_init_funcs->cga_hi_graph)(); + break; + + /* EGA modes (40 columns). */ + case EGA_TEXT_40_SP: + case EGA_TEXT_40_SP_WR: + case EGA_TEXT_40: + case EGA_TEXT_40_WR: + sc.ModeType = TEXT; + paint_screen = nt_paint_funcs->ega_text; + (*nt_init_funcs->ega_text) (); + break; + + /* EGA modes (80 columns) */ + case EGA_TEXT_80_SP: + case EGA_TEXT_80_SP_WR: + case EGA_TEXT_80: + case EGA_TEXT_80_WR: + sc.ModeType = TEXT; + paint_screen = nt_paint_funcs->ega_text; + (*nt_init_funcs->ega_text) (); + break; + + /* EGA modes (graphics). */ + case EGA_HI_FUN: + assert1(NO, "Funny graphics mode %s", get_mode_string(mode)); + FunnyPaintMode = TRUE; + case EGA_HI: + case EGA_HI_WR: + case EGA_HI_SP: + case EGA_HI_SP_WR: + sc.ModeType = GRAPHICS; + if(get_256_colour_mode()) + { +#ifdef V7VGA + if (get_seq_chain4_mode() && get_chain4_mode()) + { + paint_screen = nt_paint_funcs->v7vga_hi_graph; + (*nt_init_funcs->vga_hi_graph)(); + } + else +#endif /* V7VGA */ + { + if (get_chain4_mode()) + { +#ifdef MONITOR + if (nt_paint_funcs == &std_frozen_paint_funcs) + if (Frozen256Packed) //2 possible frozen formats + paint_screen = nt_vga_frozen_pack_std; + else + paint_screen = nt_paint_funcs->vga_graph; + else +#endif /* MONITOR */ + paint_screen = nt_paint_funcs->vga_graph; + } + else + { + if (get_char_height() == 2) + paint_screen = nt_paint_funcs->vga_med_graph; + else + paint_screen = nt_paint_funcs->vga_hi_graph; + } + (*nt_init_funcs->vga_hi_graph)(); + } + } + else + { + paint_screen = nt_paint_funcs->ega_hi_graph; + (*nt_init_funcs->ega_hi_graph)(); + } + break; + + case EGA_MED_FUN: + assert1(NO, "Funny graphics mode %s", get_mode_string(mode)); + FunnyPaintMode = TRUE; + case EGA_MED: + case EGA_MED_WR: + case EGA_MED_SP: + case EGA_MED_SP_WR: + sc.ModeType = GRAPHICS; + paint_screen = nt_paint_funcs->ega_med_graph; + (*nt_init_funcs->ega_med_graph)(); + break; + + case EGA_LO_FUN: + assert1(NO, "Funny graphics mode %s", get_mode_string(mode)); + FunnyPaintMode = TRUE; + case EGA_LO: + case EGA_LO_WR: + case EGA_LO_SP: + case EGA_LO_SP_WR: + sc.ModeType = GRAPHICS; + paint_screen = nt_paint_funcs->ega_lo_graph; + (*nt_init_funcs->ega_lo_graph)(); + break; + + default: + assert1(NO,"bad mode for host paint routine selection %d\n",(int)mode); + paint_screen = dummy_paint_screen; + break; + } + +#ifdef X86GFX + /* + * Display a message for the user if changing from a text mode to a + * graphics mode while windowed. This is because graphics modes must be + * run full-screen. + */ + { + /* + ** Tim August 92. Do not want to do a TextToGraphics() during a + ** full-screen to windowed transition. Otherwise the display gets + ** set back to full-screen! + */ + extern int BlockModeChange; /* Tim August 92, in nt_fulsc.c */ + if ((BlockModeChange == 0) && + (sc.ScreenState == WINDOWED) && + (oldModeType == TEXT) && + (sc.ModeType == GRAPHICS)) + { + TextToGraphics(); + } + else + { + + /* No call to TextToGraphics() */ + check_win_size(height); + } + } +#else + + /*................................................... Apply mode change */ + check_win_size(height); +#endif /* X86GFX */ + current_mode = mode; +} + +#ifdef BIGWIN +/* creates lut for medium or high resolution bit map stretching */ + +static void +init_lut() + +{ + long i; + + for (i = 0; i < 256; i++) + { + horiz_lut[i] = ((tiny_lut[i & 3]) + + (tiny_lut[(i >> 2) & 3] << 3) + + (tiny_lut[(i >> 4) & 3] << 6) + + (tiny_lut[(i >> 6) & 3] << 9)); + } +} + + +/* 8 bit lut version */ +/* expands a high resolution bitmap by a half horizontally */ + +void high_stretch3(buffer, length) + +unsigned char *buffer; +int length; +{ + int inp, outp; + register long temp; + + outp = SCALE(length) - 1; + + for(inp = length - 1; inp > 0;) + { + temp = horiz_lut[buffer[inp]] | (horiz_lut[buffer[inp - 1]] << 12); + inp -= 2; + + buffer[outp--] = (unsigned char) temp; + buffer[outp--] = (unsigned char) (temp >> 8); + buffer[outp--] = (unsigned char) (temp >> 16); + } +} + +void high_stretch4(buffer, length) + +unsigned char *buffer; +int length; +{ + int inp, outp; + word temp; + + outp = SCALE(length - 1); + + for(inp = length - 1; inp >= 0; inp--, outp -= 2) + { + temp = dubble_up[buffer[inp]]; + buffer[outp+1] = (unsigned char) (temp & 0xff); + buffer[outp] = (unsigned char) ((temp >> 8) & 0xff); + } +} +#endif /* BIGWIN */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Select paint routines :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static void select_paint_routines(void) +{ + /*::::::::::::::::::::::::::::::::::::::::::: Display trace information */ + + sub_note_trace2((CGA_HOST_VERBOSE | EGA_HOST_VERBOSE), + "select_paint_routine scale=%d depth=%d", + get_screen_scale(), host_display_depth); + + /*::::::::::::::::::::::::::::::::::::::::::::::: Select paint routines */ + + if(host_display_depth > 1) + { + if (get_screen_scale() == 2) + nt_paint_funcs = &std_colour_paint_funcs; + else if (get_screen_scale() == 3) + nt_paint_funcs = &big_colour_paint_funcs; + else + nt_paint_funcs = &huge_colour_paint_funcs; + + nt_init_funcs = &colour_init_funcs; + } + else + { + if (get_screen_scale() == 2) + nt_paint_funcs = &std_mono_paint_funcs; + else if (get_screen_scale() == 3) + nt_paint_funcs = &big_mono_paint_funcs; + else + nt_paint_funcs = &huge_mono_paint_funcs; + + nt_init_funcs = &mono_init_funcs; + } +} + +#ifdef MONITOR +GLOBAL void select_frozen_routines(void) +{ + if (get_screen_scale() == 2) + nt_paint_funcs = &std_frozen_paint_funcs; + else if (get_screen_scale() == 3) + nt_paint_funcs = &big_frozen_paint_funcs; + else + nt_paint_funcs = &huge_frozen_paint_funcs; + + nt_init_funcs = &frozen_init_funcs; +} +#endif /* MONITOR */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Prepare surface :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void prepare_surface(void) +{ + CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; + COORD coord; + DWORD nCharWritten; + + sub_note_trace0(ALL_ADAPT_VERBOSE, "prepare surface"); + + /*:::::::::::::::::::::::::::::: Get information on current screen size */ + + GetConsoleScreenBufferInfo(sc.OutputHandle,&ScreenInfo); + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::: Clear characters */ + + coord.X = coord.Y = 0; + FillConsoleOutputCharacter(sc.OutputHandle, ' ', + ScreenInfo.dwSize.X * ScreenInfo.dwSize.Y, + coord,&nCharWritten); + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::: Clear Attributes */ + + coord.X = coord.Y = 0; + FillConsoleOutputAttribute(sc.OutputHandle, (WORD) sc.PCBackground, + ScreenInfo.dwSize.X * ScreenInfo.dwSize.Y, + coord,&nCharWritten); + +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Global function to tell anybody what the screen scale is :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int get_screen_scale(void) { return(host_screen_scale); } + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Reverse word :::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +half_word reverser(register half_word value) +{ + return( (half_word) + (((value & 1) << 7) | + ((value & 2) << 5) | + ((value & 4) << 3) | + ((value & 8) << 1) | + ((value & 16) >> 1) | + ((value & 32) >> 3) | + ((value & 64) >> 5) | + ((value & 128) >> 7))); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Check window size ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static void check_win_size(register int height) +{ + register int width; + extern int soft_reset; + + if (! soft_reset) // we want top get the chance to integrate with + return; // console before changing size + + /*:::::::::::::::::::::::::::::::::::::::::::::: Calculate screen width */ + + if(sas_hw_at(vd_video_mode) > 0x10) + { + if(alpha_num_mode()) + width = get_chars_per_line() * get_pix_char_width(); + else + width = get_chars_per_line() * get_char_width() * + (get_256_colour_mode() ? 2 : 1); + if (width == 0) + width = CGA_WIN_WIDTH; + } + else + width = CGA_WIN_WIDTH; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Resize window */ + + if (sc.ModeType == TEXT) + { + if((current_mode_type != TEXT) || + (get_char_height() != current_char_height) || + (current_height != height) || + (current_width != width)) + { + + /* Get width and height. Note no SCALE for text modes. */ + sc.PC_W_Width = width; + sc.PC_W_Height = height*get_host_pix_height(); + textResize(); + + current_height = height; + current_width = width; + current_mode_type = TEXT; + current_char_height = get_char_height(); + } + } + else + { + if((current_mode_type != GRAPHICS) || + (current_height != height) || + (current_width != width) || + (current_bits_per_pixel != sc.BitsPerPixel) || + (current_scale != host_screen_scale)) + { + sc.PC_W_Width = SCALE(width); + sc.PC_W_Height = SCALE(height*get_host_pix_height()); + graphicsResize(); + + current_height = height; + current_width = width; + current_mode_type = GRAPHICS; + current_bits_per_pixel = sc.BitsPerPixel; + current_scale = host_screen_scale; + } + } + + sc.CharHeight = current_char_height; + + /*::::::::::::::::::::::::::::::::::::::::::: Display trace information */ + + sub_note_trace2(ALL_ADAPT_VERBOSE, + "check_win_size width = %d, height = %d", + width, height); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::: Set the VLT ??? ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void set_the_vlt(void) +{ + PALETTEENTRY vga_color[VGA_DAC_SIZE]; + int i, ind; + byte mask, top_bit; + + /*::::::::::::::::: Map DAC specified colour value to Win32 palette */ + + if(video_adapter == VGA) + { + if(get_256_colour_mode()) + { + /*.......... In 256 colour mode, create new palette entries */ + + for (i = 0; i < VGA_DAC_SIZE; i++) + { + ind = i & get_DAC_mask(); + + vga_color[i].peFlags = 0; + + vga_color[i].peRed = (BYTE) (DAC[ind].red * 4); + vga_color[i].peGreen = (BYTE) (DAC[ind].green * 4); + vga_color[i].peBlue = (BYTE) (DAC[ind].blue * 4); + } + + /*..................... Apply new colours to output palette */ + + SetPaletteEntries(sc.ColPalette, 0, VGA_DAC_SIZE, &vga_color[0]); + + /* Progs that cycle the DACs get hit by idle detect unless..*/ + + IDLE_video(); + } + else + { + /* if not in 256 colour mode then... if bit 7 of attr mode + register set then... video bits 7 & 6 = bits 3 & 2 of pixel + padding reg ('top_bit') video bits 5-0 from palette reg. + (establish by 'mask') if bit 7 of attr mode register clear + then... video bits 7 - 4 = bits 3 - 0 of pixel padding reg + ('top_bit') video bits 3-0 from palette reg. (establish by + 'mask') */ + + /*.................................... Set mask and top bit */ + + if(get_colour_select()) + { + mask = 0xf; + top_bit = (byte) ((get_top_pixel_pad() << 6) + | (get_mid_pixel_pad() << 4)); + } + else + { + mask = 0x3f; + top_bit = (byte) (get_top_pixel_pad() << 6); + } + + /*..................... Construct new Win32 palette entries */ + + for (i = 0; i < VGA_DAC_SIZE; i++) + { + /*...................... Calculate palette index number */ + + ind = i & host_plane_mask; + + /* + * If attribute controller, mode select, blink bit set in + * graphics mode, pixels 0-7 select palette entries 8-15 + * i.e. bit 3, 0->1. + */ + if ((sc.ModeType == GRAPHICS) && (bg_col_mask == 0x70)) + ind |= 8; + + ind = get_palette_val(ind); + ind = top_bit | (ind & mask); + ind &= get_DAC_mask(); + + /*........................ Construct next palette entry */ + + vga_color[i].peFlags = 0; + vga_color[i].peRed = (BYTE) (DAC[ind].red * 4); + vga_color[i].peGreen = (BYTE) (DAC[ind].green * 4); + vga_color[i].peBlue = (BYTE) (DAC[ind].blue * 4); + } + + SetPaletteEntries(sc.ColPalette, 0, VGA_DAC_SIZE, &vga_color[0]); + } + + set_palette_change_required(FALSE); + } + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Display changes */ + + if (sc.ScreenBufHandle) // only sensible in gfx context + { + /* + ** For extra safety, cos set_the_vlt() can get called in text mode. + */ + if( !SetConsoleActiveScreenBuffer( sc.ScreenBufHandle ) ){ + assert2( NO, "VDM: SCASB() failed:%#x H=%#x", + GetLastError(), sc.ScreenBufHandle ); + return; + } + if(!SetConsolePalette(sc.ScreenBufHandle, sc.ColPalette, SYSPAL_STATIC)) + assert1( NO, "SetConsolePalette() failed:%#x\n", GetLastError() ); + } + + update_vlt = FALSE; +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::: Set screen sizes - update the screen description structure :::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static void set_screen_sizes(int adaptor) +{ + UNUSED(adaptor); + + sc.PC_W_Width = SCALE(CGA_WIN_WIDTH); + sc.PC_W_Height = SCALE(CGA_WIN_HEIGHT); + sc.CharWidth = CGA_CHAR_WIDTH; + sc.CharHeight = CGA_CHAR_HEIGHT; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::; Change to plane mask ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_change_plane_mask(int plane_mask) +{ + if (host_plane_mask != plane_mask) host_plane_mask = 0xf; + + update_vlt = TRUE; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::: Dummy Paint Routines for all the IBM screen modes :::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static void dummy_paint_screen(int offset, int host_x, int host_y, + int width, int height) +{ + UNUSED(offset); + UNUSED(host_x); + UNUSED(host_y); + UNUSED(width); + UNUSED(height); + + sub_note_trace5((CGA_HOST_VERBOSE | EGA_HOST_VERBOSE), + "dummy_paint_screen off=%d x=%d y=%d width=%d h=%d", + offset, host_x, host_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Set downloaded font ???? :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_set_downloaded_font(int value) +{ + UNUSED(value); + + sub_note_trace1((CGA_HOST_VERBOSE | EGA_HOST_VERBOSE), + "host_set_downloaded_font value=%d", value); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::: Free Font ::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_free_font(int index) +{ + UNUSED(index); + + sub_note_trace0(EGA_HOST_VERBOSE,"nt_free_font - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::: Select font :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_select_fonts(int font1, int font2) +{ + UNUSED(font1); + UNUSED(font2); + + sub_note_trace0(EGA_HOST_VERBOSE,"nt_select_fonts - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Update fonts ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_update_fonts(void) { } + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Set palette :::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_set_palette(PC_palette *palette, int size) +{ + UNUSED(palette); + UNUSED(size); + + sub_note_trace0(EGA_HOST_VERBOSE,"nt_set_palette - NOT SUPPORTED"); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Set screen scale ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_set_screen_scale(int scale) +{ + if (scale != host_screen_scale) + { + host_screen_scale = scale; + + /* + * Don't want to do any painting if this is called on initialisation + * and sc.PC_W_Width is as good a variable as any to check for this. + */ + if (sc.PC_W_Width) + { + select_paint_routines(); + nt_set_paint_routine(current_mode, current_height); + nt_mark_screen_refresh(); + } + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::: Set border colour ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_set_border_colour(int colour) +{ + UNUSED(colour); + + sub_note_trace0(ALL_ADAPT_VERBOSE,"nt_set_border_colour - NOT SUPPORTED"); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Resize window :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* +***************************************************************************** +** windowSize() resizes the console window to the specified height and width. +***************************************************************************** +** Called from resizeWindow() below. +*/ +VOID windowSize IFN4( int, w, int, h, int, top, int, left ) +{ + SMALL_RECT WinSize; + + WinSize.Top = top; + WinSize.Left = left; + WinSize.Bottom = top + h - 1; + WinSize.Right = left + w - 1; + +#ifndef PROD + //fprintf(trace_file, "newW: %d.%d at %d.%d\n", h, w, top, left); +#endif + if( !SetConsoleWindowInfo( sc.OutputHandle, TRUE, &WinSize ) ) + assert3( NO, "VDM: SetConsoleWindowInfo() w=%d h=%d failed:%#x", + w, h, GetLastError() ); +} + +/* +***************************************************************************** +** bufferSize() resizes the console buffer to the specified height and width. +***************************************************************************** +** Called from resizeWindow() below. +*/ +VOID bufferSize IFN2( int, w, int, h ) +{ + COORD ScrSize; + + ScrSize.X = w; + ScrSize.Y = h; +#ifndef PROD + //fprintf(trace_file, "newB: %d.%d\n", h, w); +#endif + if( !SetConsoleScreenBufferSize( sc.OutputHandle, ScrSize ) ) + assert3( NO, "VDM: SetCons...BufferSize() w=%d h=%d failed:%#x", + w, h, GetLastError() ); +} + +/* +***************************************************************************** +* resizeWindow() +***************************************************************************** +* Sizes the console window and buffer as appropriate. +* +* The buffer must be able at all times to keep everything displayed +* in the window. +* So we check if the displayed portion would fall out of the buffer +* and shrink the window appropriately. +* +* Then allocate the new buffer. This may affect the maximum window +* size, so retrieve these values. +* +* Now the desired proportions of the Window are clipped to the +* (eventually just updated) maximum, and if different from what +* we have already, the change is made. +* +* In order to keep "screen flashing" to a minimum, try to restore +* the displayed portion (top and left) of the buffer. +*/ +VOID resizeWindow IFN2( int, w, int, h ) +{ +#define MIN(a,b) ((a)<(b)?(a):(b)) + + int oldTop, oldLeft; /* present values */ + int newTop, newLeft;/* new values */ + COORD oldW, /* present window size */ + oldB; /* present buffer size */ + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + + if( h > 50 ){ + /* Shouldn't get this anymore said Tim */ + assert1( NO, "VDM: resizeWindow() clipping height:%d", h ); + h = 50; + } + if( !GetConsoleScreenBufferInfo( sc.OutputHandle, &bufferInfo) ) + assert1( NO, "VDM: GetConsoleScreenBufferInfo() failed:%#x", + GetLastError() ); + + oldTop = bufferInfo.srWindow.Top; + oldLeft = bufferInfo.srWindow.Left; + + oldW.X = bufferInfo.srWindow.Right - bufferInfo.srWindow.Left + 1; + oldW.Y = bufferInfo.srWindow.Bottom - bufferInfo.srWindow.Top + 1; + oldB = bufferInfo.dwSize; +#ifndef PROD + //fprintf(trace_file, "resz: %d.%d\n", h, w); + //fprintf(trace_file, "oldW: %d.%d\n", oldW.Y, oldW.X); + //fprintf(trace_file, "maxW: %d.%d\n", bufferInfo.dwMaximumWindowSize.Y, bufferInfo.dwMaximumWindowSize.X); + //fprintf(trace_file, "oldB: %d.%d\n", oldB.Y, oldB.X); +#endif + /* + * Reduce window width and height as necessary: + */ + if ( bufferInfo.srWindow.Bottom >= h + || bufferInfo.srWindow.Right >= w ) { + windowSize( MIN(w,oldW.X), MIN(h,oldW.Y), 0, 0); + } + + /* + * Change Buffer width and height as required. + */ + if ( oldB.X || h != oldB.Y ) { + bufferSize( w, h ); + + /* + * This increase in Buffer size may have affected maximum + * possible window sizes: + */ + if( !GetConsoleScreenBufferInfo( sc.OutputHandle, &bufferInfo) ) + assert1( NO, "VDM: GetConsoleScreenBufferInfo() failed:%#x", + GetLastError() ); +#ifndef PROD + //fprintf(trace_file, "maxW: %d.%d\n", bufferInfo.dwMaximumWindowSize.Y, bufferInfo.dwMaximumWindowSize.X); +#endif + } + /* + ** Clip requested values to Window maximum and + ** compute new (possible) top and left values. + */ + + newLeft = w - bufferInfo.dwMaximumWindowSize.X; + if ( newLeft > 0 ) { + w = bufferInfo.dwMaximumWindowSize.X; + } else + newLeft = 0; + + newTop = h - bufferInfo.dwMaximumWindowSize.Y; + if ( newTop > 0 ) { + h = bufferInfo.dwMaximumWindowSize.Y; + } else + newTop = 0; + + /* + * Check if we need to enlarge the window now. + * Settle for old top and left if they were smaller. + * This avoids unnecessary updates in the window. + */ + if ( w > oldW.X || h > oldW.Y ) + windowSize( w, h, MIN(newTop,oldTop), MIN(newLeft,oldLeft) ); + +} /* end of resizeWindow() */ + +/* +** Controls the size of the window when in a text mode. +** scale=2 selects normal (small) size +** scale=3 selects bit 1.5x +** If this function is called before the SoftPC window has been created, +** the "sv_screen_scale" variable needs to be changed. This governs +** the SCALE() macro, which is used just to specify the window +** dimensions at creation. If the SoftPC window already exists then the +** size is changed by a more complex sequence. +*/ + +//Used by the text paint functions +GLOBAL int now_height = 80, now_width = 50; + +void textResize(void) +{ + + if(sc.PC_W_Height && sc.PC_W_Width && + get_host_char_height() && get_pix_char_width()) + { + now_height = sc.PC_W_Height/get_host_char_height(); + now_width = sc.PC_W_Width / get_pix_char_width(); + + select_paint_routines(); + nt_change_mode(); + + resizeWindow(now_width, now_height); /* Tim, September 92 */ + } +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:: ::*/ +/*:: graphicsResize: ::*/ +/*:: ::*/ +/*:: Resize SoftPC window when in a graphics mode by selecting a new ::*/ +/*:: active screen buffer. ::*/ +/*:: ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +void graphicsResize(void) +{ + DWORD headerSize; + LPBITMAPINFO infoStructPtr; + + if (sc.ScreenState == FULLSCREEN) + return; + + /* Destroy previous data. */ + closeGraphicsBuffer(); /* Tim Oct 92 */ + + if (sc.ConsoleBufInfo.lpBitMapInfo != NULL) + free((char *) sc.ConsoleBufInfo.lpBitMapInfo); + + /* + * Create a `BITMAPINFO' structure - sc.PC_W_Width pixels x + * sc.PC_W_Height pixels x sc.BitsPerPixel bits-per-pixel. + */ + headerSize = CreateSpcDIB(sc.PC_W_Width, + sc.PC_W_Height, + sc.BitsPerPixel, + DIB_PAL_COLORS, + 0, + (COLOURTAB *) NULL, + &infoStructPtr); + + /* Initialise the console info structure. */ + sc.ConsoleBufInfo.dwBitMapInfoLength = headerSize; + sc.ConsoleBufInfo.lpBitMapInfo = infoStructPtr; + sc.ConsoleBufInfo.dwUsage = DIB_PAL_COLORS; + + /* Create a screen buffer using the above `BITMAPINFO' structure. */ + sc.ScreenBufHandle = + CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CONSOLE_GRAPHICS_BUFFER, + &sc.ConsoleBufInfo); + + if (sc.ScreenBufHandle == (HANDLE)-1) + { + sc.ScreenBufHandle = NULL; + assert1( NO, "VDM: graphics screen buffer creation failed:%#x\n", + GetLastError()); + } + + /* 'cos old palette discarded with close buffer */ + if (sc.ColPalette == (HPALETTE)0) + { + CreateDisplayPalette(); + set_palette_change_required(TRUE); + } + + /* save the handle away to a useful place */ + MouseDetachMenuItem(TRUE); + sc.ActiveOutputBufferHandle = sc.ScreenBufHandle; + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + + /* + * Make it the current screen buffer, which resizes the window + * on the display. + */ + SetConsoleActiveScreenBuffer(sc.ScreenBufHandle); + + /* + * Get a pointer to the last line of the bitmap to build + * upside-down pictures. + */ + sc.BitmapLastLine = (char *) sc.ConsoleBufInfo.lpBitMap + + (sc.PC_W_Height - 1) * + BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:: ::*/ +/*:: CreateSpcDIB: ::*/ +/*:: ::*/ +/*:: Create a new SoftPC device independent bitmap. ::*/ +/*:: Parameters: ::*/ +/*:: width - width of the bitmap in pixels. ::*/ +/*:: height - height of the bitmap in pixels. ::*/ +/*:: bitsPerPixel - number of bits representing one pixel in the ::*/ +/*:: bitmap. ::*/ +/*:: wUsage - type of bitmap to create, can be DIB_PAL_COLORS,::*/ +/*:: DIB_RGB_COLORS or DIB_PAL_INDICES. ::*/ +/*:: DIBColours - Only interrogated for DIB_RGB_COLORS bitmaps, ::*/ +/*:: defines the number of entries in the colour ::*/ +/*:: table. If set to USE_COLOURTAB the colour table ::*/ +/*:: contains the same number of entries as the ::*/ +/*:: `colours' table, otherwise DIBColours contains ::*/ +/*:: the actual number of entries to be used. ::*/ +/*:: colours - Only interrogated for DIB_RGB_COLORS bitmaps, ::*/ +/*:: points to a COLOURTAB structure which contains ::*/ +/*:: the RGB values to be loaded into the bitmap's ::*/ +/*:: colour table. ::*/ +/*:: infoPtr - The address in which to return a pointer to the ::*/ +/*:: BITMAPINFO structure allocated by this routine. ::*/ +/*:: ::*/ +/*:: Return value: ::*/ +/*:: The size of the BITMAPINFO structure allocated on success, -1 ::*/ +/*:: on failure. ::*/ +/*:: ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL DWORD CreateSpcDIB(int width, int height, int bitsPerPixel, + WORD wUsage, int DIBColours, + COLOURTAB *colours, BITMAPINFO **infoPtr) +{ + PBITMAPINFO pDibInfo; /* Returned data structure. */ + int i, /* Counting variable. */ + maxColours, /* Maximum number of colours. */ + coloursUsed, /* Value to be put in biClrUsed field. */ + nActualColours, /* Number of colours in RGB_COLOURS bitmap. */ + tabSize; /* Size of colour table to allocate. */ + DWORD allocSize; /* Total size to allocate. */ + + /* Work out size of DIB colour table. */ + maxColours = 1 << bitsPerPixel; + switch (wUsage) + { + + case DIB_PAL_COLORS: + tabSize = maxColours * sizeof(WORD); + coloursUsed = 0; + break; + + case DIB_RGB_COLORS: + if (colours == NULL) + return((DWORD) -1); + nActualColours = (DIBColours == USE_COLOURTAB) ? + colours->count : + DIBColours; + tabSize = nActualColours * sizeof(RGBQUAD); + coloursUsed = nActualColours; + break; + + case DIB_PAL_INDICES: + tabSize = 0; + coloursUsed = 0; + break; + + default: + always_trace0("Illegal wUsage parameter passed to CreateSpcDIB."); + return((DWORD) -1); + + } + + /* Allocate space for the BITMAPINFO structure. */ + allocSize = sizeof(BITMAPINFOHEADER) + tabSize; + check_malloc(pDibInfo, allocSize, BITMAPINFO); + + /* Initialise BITMAPINFOHEADER. */ + pDibInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pDibInfo->bmiHeader.biWidth = width; + pDibInfo->bmiHeader.biHeight = -height; + pDibInfo->bmiHeader.biPlanes = 1; + pDibInfo->bmiHeader.biBitCount = (WORD) bitsPerPixel; + pDibInfo->bmiHeader.biCompression = BI_RGB; + pDibInfo->bmiHeader.biSizeImage = width * height / 8 * bitsPerPixel; + pDibInfo->bmiHeader.biXPelsPerMeter = 0; + pDibInfo->bmiHeader.biYPelsPerMeter = 0; + pDibInfo->bmiHeader.biClrUsed = coloursUsed; + pDibInfo->bmiHeader.biClrImportant = 0; + + /* Initialise colour table. */ + switch (wUsage) + { + + case DIB_PAL_COLORS: + + /* + * Colour table is an array of WORD indexes into currently realized + * palette. + */ + for (i = 0; i < maxColours; i++) + ((WORD *) pDibInfo->bmiColors)[i] = (WORD) i; + break; + + case DIB_RGB_COLORS: + + /* + * Colour table is an array of RGBQUAD structures. If the `colours' + * array contains fewer than `nActualColours' entries the colour + * table will not be completely filled. In this case `colours' is + * repeated until the table is full. + */ + for (i = 0; i < nActualColours; i++) + { + pDibInfo->bmiColors[i].rgbBlue = + colours->blue[i % colours->count]; + pDibInfo->bmiColors[i].rgbGreen = + colours->green[i % colours->count]; + pDibInfo->bmiColors[i].rgbRed = + colours->red[i % colours->count]; + pDibInfo->bmiColors[i].rgbReserved = 0; + } + break; + + case DIB_PAL_INDICES: + + /* No colour table DIB uses system palette. */ + break; + + default: + break; + + } + *infoPtr = pDibInfo; + return(allocSize); +} + + +/* Holding place for stub functions */ + +void nt_mode_select_changed(int dummy) +{ + UNUSED(dummy); +#ifndef PROD + fprintf(trace_file, "WARNING - nt_mode_select_changed\n"); +#endif +} + +void nt_color_select_changed(int dummy) +{ + UNUSED(dummy); +#ifndef PROD + fprintf(trace_file, "WARNING - nt_color_select_changed\n"); +#endif +} + +void nt_screen_address_changed(int lo, int hi) +{ + UNUSED(lo); + UNUSED(hi); + + sub_note_trace0(EGA_HOST_VERBOSE, "WARNING - nt_screen_address_changed\n"); +} + +void nt_scroll_complete() { } + +void host_stream_io_update(half_word * buffer, word count) +{ + DWORD dwBytesWritten; + + WriteConsoleA(sc.OutputHandle, + buffer, + count, + &dwBytesWritten, + NULL + ); + flush_count = 0; +} diff --git a/private/mvdm/softpc.new/host/src/nt_hfx.c b/private/mvdm/softpc.new/host/src/nt_hfx.c new file mode 100644 index 000000000..fc2bd0f59 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_hfx.c @@ -0,0 +1,195 @@ +#include "host_def.h" +#include "insignia.h" +/* + * SoftPC Revision 2.0 + * + * Title : unix_hfx.c + * + * Description : Stubbs for HFX + * + */ + +#include <stdio.h> +#include "xt.h" +#include "host_hfx.h" +#include "hfx.h" +#include "debug.h" + +void get_hostname IFN2(int, fd, char *, name) +{ +} + +void get_host_fd IFN2(char *, name,int, fd) +{ +} + +void init_fd_hname() +{ +} + +void host_concat IFN3(char *, path,char *, name,char *, result) +{ +} + +word host_create IFN4(char *, name, word, attr, half_word, create_new, word *, fd) +{ + return (0); +} + +void host_to_dostime IFN3(long, secs_since_70, word *, date, word *, time) +{ +} + +long host_get_datetime IFN2(word *, date,word *, thetime) +{ + return (0); +} + +int host_set_time IFN2(word, fd, long, hosttime) +{ + return (0); +} + + +word host_open IFN6(char *, name, half_word, attrib, word *, fd, double_word *, size, word *, date, word *, thetime) +{ + return (0); +} + +/* General purpose file move function. This was added for use by the new + general purpose truncate code. It can copy between file systems, can + overwrite the existing destination file, and can pad the destination + file to the given length if the source file is less than that length. */ +int mvfile IFN3(char *, from, char *, to, int, length) +{ + return (0); +} + +word host_truncate IFN2(word, fd, long, size) +{ + return (0); +} + +word host_close IFN1(word, fd) +{ + word xen_err = 0; + return(0); +} + +word host_commit IFN1(word, fd) +{ + return(0); +} + +word host_write IFN4(word, fd, unsigned char *, buf, word, num, word *, count) +{ + return (0); +} + +word host_read IFN4(word, fd, unsigned char *, buf, word, num, word *, count) +{ + return(0); +} + +word host_delete IFN1(char *, name) +{ + return(0); +} + +int hfx_rename IFN2(char *, from,char *, to) +{ + return(0); +} + + +word host_rename IFN2(char *, from, char *, to) +{ + word xen_err = 0; + return(0); +} + + +half_word host_getfattr IFN1(char *, name) +{ + half_word attr; + return(0); +} + +word host_get_file_info IFN4(char *, name, word *, thetime, word *, date, double_word *, size) +{ + return(0); +} + +word host_set_file_attr IFN2(char *, name, half_word, attr) +{ + return(0); +} + +word host_lseek IFN4(word, fd, double_word, offset,int, whence, double_word *, position) +{ + return(0); +} + +word host_lock IFN3(word, fd, double_word, start, double_word, length) +{ + return(0); +} + +word host_unlock IFN3(word, fd, double_word, start, double_word, length) +{ + return(0); +} + +host_check_lock() +{ + return(0); +} + +void host_disk_info IFN2(DOS_DISK_INFO *, disk_info, int, drive) +{ +} +/* + * + * Remove directory function. + */ +word host_rmdir IFN1(char *, host_path) +{ + return (0); +} + +/* + * + * Make directory function. + */ +word host_mkdir IFN1(char *, host_path) +{ + return (0); +} + +/* + * + * Change directory function. This function only validates the path + * given. DOS decides whether to actually change directory at a higher + * level. Success is returned if the path exists and is a directory. + * If the path exists but the file is not a directory, then a special + * code is returned, as to return error_path_not_found would be + * ambiguous. + */ +word host_chdir IFN1(char *, host_path) +{ + return (0); +} + + +/* + * + * Function to return the volume ID of a network drive. + * Eleven characters are available for the name to be output. + * + * The last field in the network drive path it output unless it + * is more than eleven characters long in which case ten characters + * are output with an appended tilde. + */ +void host_get_volume_id IFN2(char *, net_path, char *, volume_id) +{ +} diff --git a/private/mvdm/softpc.new/host/src/nt_hosts.c b/private/mvdm/softpc.new/host/src/nt_hosts.c new file mode 100644 index 000000000..bbf99e7a5 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_hosts.c @@ -0,0 +1,343 @@ +/*************************************************************************** + * * + * PROGRAM : HOST_UIS.c * + * * + * PURPOSE : Host UI code * + * * + ****************************************************************************/ + + +#include <windows.h> +#include "conapi.h" +#include "insignia.h" +#include "host_def.h" + +#include "xt.h" +#include "gvi.h" +#include "gmi.h" +#include <stdio.h> +#include "trace.h" +#include "debug.h" +#include "host_rrr.h" + +#include "nt_graph.h" +#include "nt_event.h" +#include "nt_uis.h" +#include "nt_reset.h" + +#ifdef HUNTER +#include "nt_hunt.h" +#endif /*HUNTER*/ + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::: Global variables */ + +HANDLE InstHandle; + + +CONSOLE_CURSOR_INFO StartupCursor; + +/*:::::::::::::::::::::::::::::::::::::::: Fast graphics associated defines */ + +BYTE Red[] = { 0, 0, 0, 0, 128, 128, 128, 192, 128, 0, 0, + 0, 255, 255, 255, 255 }; + +BYTE Green[]={ 0, 0, 128, 128, 0, 0, 128, 192, 128, 0, 255, + 255, 0, 0, 255, 255 }; + +BYTE Blue[] ={ 0, 128, 0, 128, 0, 128, 0, 192, 128, 255, 0, + 255, 0, 255, 0, 255 }; + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::: External functions */ + +LONG nt_process_event(HWND hWnd, WORD message, LONG wParam, LONG lParam); + +/*::::::::::::::::::::::::::::::::::::::::::::: Internal function protocols */ + +BOOL SoftInit(void); +WORD HeartBeat(HWND hWnd, WORD msg, int nIDEvent, DWORD dwTime); + +PSTR String(WORD StrResID); +void InitScreenDesc(void); + +#ifdef HUNTER +void HunterMenuMake(void); +#endif /* HUNTER */ + +HANDLE SCS_hStdIn=0; +HANDLE SCS_hStdOut=0; +HANDLE SCS_hStdErr=0; + +/**************************************************************************** + * * + * FUNCTION : init_host_uis() * + * * + * PURPOSE : Creates the main app. window, calls an initialization * + * functions * + * * + ****************************************************************************/ + +int init_host_uis() +{ + InitScreenDesc(); + + if(CreateDisplayPalette()) + { + SelectPalette(sc.DispDC,sc.ColPalette,0);/* Select foreground palette */ + } + + return(1); +} + +/**************************************************************************** + * * + * FUNCTION : SetupConsoleMode() * + * * + * PURPOSE : Setup console mode and get handles * + * * + ****************************************************************************/ + +void SetupConsoleMode(void) +{ + DWORD mode; + + /*::::::::::::::::::::::::::::::::::::::::::: Set console input mode */ + + if(!GetConsoleMode(sc.InputHandle, &sc.OrgInConsoleMode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + mode = sc.OrgInConsoleMode & + ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); + if (!host_stream_io_enabled) + mode |= (ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + + /*.............................................. Set new console mode */ + + if(!SetConsoleMode(sc.InputHandle,mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + /*::::::::::::::::::::::::::::::::::::::::::: Set console output mode */ + + if(!GetConsoleMode(sc.OutputHandle, &sc.OrgOutConsoleMode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + /*.............................................. Set new console mode */ + + if(!stdoutRedirected && !host_stream_io_enabled) + { + mode = sc.OrgOutConsoleMode & + ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT); + + if(!SetConsoleMode(sc.OutputHandle,mode)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + } + + if(!GetConsoleCursorInfo(sc.OutputHandle, &StartupCursor)) + { + assert1(NO, "NTVDM:can't get initial cursor size. Err %d", GetLastError()); + /* add own defaults */ + StartupCursor.dwSize = 20; + StartupCursor.bVisible = TRUE; + } + if(!GetConsoleScreenBufferInfo(sc.OutputHandle, &sc.ConsoleBuffInfo)) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(), __FILE__,__LINE__); + +} + + +/**************************************************************************** + * * + * FUNCTION : InitScreenDesc * + * * + * PURPOSE : Initialise screen description structure * + * * + ****************************************************************************/ + +void InitScreenDesc(void) +{ +SECURITY_ATTRIBUTES sa; + + /*::::::::::::::::::::::::::::::::::::::::::: Get console output handle */ + + if((sc.OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + // + // Save this handle as the active handle until a new one is + // selected. + // + + sc.ActiveOutputBufferHandle = sc.OutputHandle; + sc.ScreenBufHandle = (HANDLE)0; + + /*:::::::::::::::::::::::::::::::::::::::::::: Get console input handle */ + + if((sc.InputHandle = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + + /*:::::::::::::::::::::::::::::: check out if stdin has been redirected */ + + if(GetFileType(sc.InputHandle) != FILE_TYPE_CHAR) + { + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + sc.InputHandle = CreateFile("CONIN$",GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa,OPEN_EXISTING, 0, NULL); + + if(sc.InputHandle == (HANDLE)-1) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + else{ + SetStdHandle (STD_INPUT_HANDLE,sc.InputHandle); + } + } + + /*:::::::::::::::::::::::::::: check out if stdout has been redirected */ + + if(GetFileType(sc.OutputHandle) != FILE_TYPE_CHAR) + { + stdoutRedirected = TRUE; + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + sc.OutputHandle = CreateFile("CONOUT$",GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa,OPEN_EXISTING, 0, NULL); + + if(sc.OutputHandle == (HANDLE)-1) + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + else { + SetStdHandle (STD_OUTPUT_HANDLE,sc.OutputHandle); + SetStdHandle (STD_ERROR_HANDLE,sc.OutputHandle); + } + } + + // Keep SCS in sync with these handles for starting non-dos binaries + SCS_hStdIn = sc.InputHandle; + SCS_hStdOut = sc.OutputHandle; + SCS_hStdErr = sc.OutputHandle; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::: Setup console mode */ + + SetupConsoleMode(); + +#ifdef HUNTER + HunterMenuMake(); +#endif /*HUNTER*/ + + /*::::::::::::::::::::::::::: Tell console to post us a closedown event */ + + // we only want notification for DOS NTVDM runnig on an existing console + if (!VDMForWOW && !DosSessionId) + SetLastConsoleEventActive(); + sc.StaticPalette = TRUE; + sc.FontsAreOpen = FALSE; +} +/**************************************************************************** + * * + * FUNCTION : BOOL CreateDisplayPalette(void) * + * * + * PURPOSE : Create logical palette * + * Assumes Colour monitor supporting 16 colours * + * * + ****************************************************************************/ + +BOOL CreateDisplayPalette(void) +{ + register int i; + register PALETTEENTRY *PalEntry; + NPLOGPALETTE LogPalette; /* Pointer to logical palette */ + + /*::::::: Allocate memory for a logical palette with PALETTESIZE entries */ + + LogPalette = (NPLOGPALETTE) LocalAlloc(LMEM_FIXED, + (sizeof(LOGPALETTE) + + (sizeof(PALETTEENTRY) * PALETTESIZE))); + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Allocation failed !! */ + + if(!LogPalette) return(FALSE); /* Function failed, no memory */ + + /*::: Set the size and version fields of the logical palette structure. */ + + LogPalette->palVersion = 0x300; + LogPalette->palNumEntries = PALETTESIZE; + + /*::::::::::::::::::: Fill in intensities for all palette entry colors */ + + for(i=0,PalEntry=LogPalette->palPalEntry; i < PALETTESIZE;i++,PalEntry++) + { + if(i < sizeof(Red)/sizeof(BYTE)) + { + PalEntry->peRed = Red[i]; PalEntry->peGreen = Green[i]; + PalEntry->peBlue = Blue[i]; + } + else + { + PalEntry->peRed = PalEntry->peGreen = PalEntry->peBlue = 0; + } + + PalEntry->peFlags = sc.StaticPalette ? 0 : PC_RESERVED; + } + + /*:::::::: Create a logical color palette from the LOGPALETTE structure */ + + sc.ColPalette = CreatePalette((LPLOGPALETTE) LogPalette); + LocalFree((HANDLE)LogPalette); + + return(sc.ColPalette ? TRUE : FALSE); +} + + +/*============================================================================ +Function to display a menu option on the Console system menu. This is used for +the control of Trapper. +============================================================================*/ + +#ifdef HUNTER +void HunterMenuMake(void) +{ +HMENU hTest,hTrapperPopup,hMainPopup,hErrorPopup; +static BOOL bTrapperMenuFlag=FALSE; + +if(!bTrapperMenuFlag) + { + /*======================================================================== + The Menus have been drawn once already. Need to delete these and reappend + them to the Console menu for the new output buffer. Isn't Console just such + a bore? + ========================================================================*/ + + DestroyMenu(hTrapperPopup); + DestroyMenu(hMainPopup); + DestroyMenu(hErrorPopup); + } + +hTrapperPopup = CreateMenu(); +hMainPopup = CreateMenu(); +hErrorPopup = CreateMenu(); + +AppendMenu(hMainPopup,MF_STRING,IDM_MFAST,"&Fast forward"); +AppendMenu(hMainPopup,MF_STRING,IDM_MNEXT,"&Next screen"); +AppendMenu(hMainPopup,MF_STRING,IDM_MPREV,"&Prev screen"); +AppendMenu(hMainPopup,MF_STRING,IDM_MSHOW,"&Show screen"); +AppendMenu(hMainPopup,MF_STRING,IDM_MCONT,"&Continue"); +AppendMenu(hMainPopup,MF_STRING,IDM_MABOR,"&Abort"); + +AppendMenu(hErrorPopup,MF_STRING,IDM_EFLIP,"&Flip screen"); +AppendMenu(hErrorPopup,MF_STRING,IDM_ENEXT,"&Next error"); +AppendMenu(hErrorPopup,MF_STRING,IDM_EPREV,"&Prev error"); +AppendMenu(hErrorPopup,MF_STRING,IDM_EALL,"&All errors"); +AppendMenu(hErrorPopup,MF_STRING,IDM_ECLEA,"&Clear errors"); + +AppendMenu(hTrapperPopup,MF_POPUP,hMainPopup,"&Main"); +AppendMenu(hTrapperPopup,MF_POPUP,hErrorPopup,"&Error"); + +/* if graphics mode, then use sc.ScreenBuffer */ + +/* hTest = ConsoleMenuControl(sc.ScreenBuffer,IDM_TRAPPER,IDM_ECLEA); */ + +/* else text mode, then use sc.OutputHandle */ +hTest = ConsoleMenuControl(sc.OutputHandle,IDM_TRAPPER,IDM_ECLEA); + +AppendMenu(hTest,MF_POPUP,hTrapperPopup,"&Trapper"); +bTrapperMenuFlag=TRUE; /* draw the trapper menu just once */ +} +#endif /* HUNTER */ diff --git a/private/mvdm/softpc.new/host/src/nt_hunt.c b/private/mvdm/softpc.new/host/src/nt_hunt.c new file mode 100644 index 000000000..bc28e18ea --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_hunt.c @@ -0,0 +1,250 @@ +#include "windows.h" +#include "host_def.h" +#include "insignia.h" +/*[ +Name: hunt.c + Derived From: X_hunt.c ( base 2.0 ) + Author: gvdl ( Original by Mike McCusker ) + Created On: 3 May 1991 +Sccs ID: 07/29/91 @(#)hunt.c 1.7 + Purpose: Contains all host_dependent code for hunter + + (c)Copyright Insignia Solutions Ltd., 1990. All rights reserved. + +]*/ + +#include <stdio.h> +#include <errno.h> +#include TypesH + + +#include "xt.h" +#include "ios.h" +#include CpuH +#include "sas.h" +#include "bios.h" +#include "gvi.h" +#include "cga.h" +#include "error.h" +#include "config.h" +#include "nt_uis.h" + + + +#include "debug.h" + +#ifdef HUNTER +#include "hunter.h" + + +extern HANDLE InstHandle; + +/* +* ============================================================================ +* Global Defines and Declarations +* ============================================================================ +*/ +GLOBAL HANDLE TrapperDump = -1; + +LOCAL VOID nt_hunter_init IPT1(SHORT, mode); +LOCAL VOID nt_hunter_activate_menus IPT0(); +LOCAL VOID host_flip_video_ind IPT0(); +LOCAL VOID nt_hunter_mark_error IPT2(int, x, int, y); +LOCAL VOID nt_hunter_erase_error IPT0(); +LOCAL VOID nt_hunter_draw_box IPT1(BOX *, b); +LOCAL ULONG nt_hunter_image_check IPT0(); +LOCAL VOID nt_hunter_display_image IPT0(); + + + +DWORD CreateTrapperWindow IPT0(); +LONG FAR PASCAL TrapperWindowEvents IPT4(HWND, hTrapWnd, WORD, message, LONG, wParam, LONG, lParam); + + + + + +GLOBAL HUNTER_HOST_FUNCS hunter_host_funcs = +{ +nt_hunter_init, +nt_hunter_activate_menus, +host_flip_video_ind, +nt_hunter_mark_error, +nt_hunter_mark_error, +nt_hunter_draw_box, +nt_hunter_draw_box, +nt_hunter_image_check, +nt_hunter_display_image, +}; + + +LOCAL BOX lastBox; /* last box drawn during movement */ + +HWND hTrapWnd; + +LOCAL VOID nt_hunter_activate_menus IFN0() +{ +printf("nt_hunter_activate_menus() called\n"); +} + +LOCAL VOID host_flip_video_ind IFN0() +{ +printf("host_flip_video() called\n"); +} + + + +LOCAL VOID nt_hunter_init IFN1(SHORT, mode) +{ + char *dumpFile; + + /* Read environment to see if we have a trapper file to open. */ + if ((dumpFile = host_getenv("HUDUMPFILE")) != NULL) + { + TrapperDump = CreateFile((LPCTSTR) dumpFile, + (DWORD) GENERIC_WRITE, + (DWORD) 0, + (LPSECURITY_ATTRIBUTES) NULL, + (DWORD) CREATE_ALWAYS, + (DWORD) FILE_ATTRIBUTE_NORMAL, + (HANDLE) 0); + if (TrapperDump == (HANDLE) -1) + printf("Failed to open trapper file \"%s\".\n", dumpFile); + } +} + +LOCAL VOID nt_hunter_draw_box IFN1(BOX *, b) +{ +HDC hDC; +HPEN hPen; +int x1,x2,y1,y2; + + +x1=(b->top_x >> 1); +y1=(b->top_y >> 1); +x2=(b->bot_x >> 1); +y2=(b->bot_y >> 1); + +hDC=GetDC(hTrapWnd); +SetROP2(hDC,R2_COPYPEN); +hPen=CreatePen(PS_SOLID,0,RGB(0,255,0)); +SelectObject(hDC,hPen); + +MoveToEx(hDC,x1,y1,NULL); +LineTo(hDC,x1,y2); +LineTo(hDC,x2,y2); +LineTo(hDC,x2,y1); +LineTo(hDC,x1,y1); +DeleteObject(hPen); +ReleaseDC(hTrapWnd,hDC); +} + + +LOCAL VOID nt_hunter_mark_error IFN2(int, x, int, y) +{ +int x1,x2,y1,y2; +HPEN hPen; +HDC hDC; + + +x1=x-4; +y1=y-4; +x2=x+4; +y2=y+4; + + +hDC=GetDC(hTrapWnd); +SetROP2(hDC,R2_XORPEN); +hPen=CreatePen(PS_SOLID,0,RGB(0,255,0)); +SelectObject(hDC,hPen); + +/* +* Draw cross in the approximate region of error +*/ + +MoveToEx(hDC,x1,y,NULL); +LineTo(hDC,x2,y); +MoveToEx(hDC,x,y1,NULL); +LineTo(hDC,x,y2); +DeleteObject(hPen); +ReleaseDC(hTrapWnd,hDC); + +} + +LOCAL VOID nt_hunter_erase_error IFN0() +{ +InvalidateRect(hTrapWnd,NULL,TRUE); +} + +LOCAL ULONG nt_hunter_image_check IFN0() +{ +printf("nt_hunter_image_check() called\n"); +return FALSE; +} + +LOCAL VOID nt_hunter_display_image IFN0() +{ +printf("nt_hunter_display_image() called\n"); +} + + +DWORD CreateTrapperWindow IFN0() +{ +WNDCLASS WndCls; +MSG msg; +HDC hDC; +HPEN hPen; + + +WndCls.style = CS_HREDRAW | CS_VREDRAW; +WndCls.lpfnWndProc = (WNDPROC) TrapperWindowEvents; +WndCls.hInstance = GetModuleHandle(NULL); +WndCls.hIcon = NULL; +WndCls.hCursor = LoadCursor(NULL,IDC_ARROW); +WndCls.hbrBackground = GetStockObject(BLACK_BRUSH); +WndCls.lpszMenuName = NULL; +WndCls.lpszClassName = (LPSTR) "Trapper"; +WndCls.cbClsExtra = 0; +WndCls.cbWndExtra = 0; + +RegisterClass(&WndCls); + +hTrapWnd = CreateWindow("Trapper", "Trapper",WS_THICKFRAME | WS_OVERLAPPED | + WS_CAPTION, + 200,200,520,440, (HWND) NULL, NULL, + GetModuleHandle(NULL), (LPSTR) NULL); + +ShowWindow(hTrapWnd,SW_SHOWNORMAL); +UpdateWindow(hTrapWnd); + +while(GetMessage(&msg, NULL, NULL, NULL)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); /* Dispatch Message to event handler */ + } + +} + +/*============================================================================ + +Function to handle the messages passed to the trapper monitor window. +Since we send no messages to it, the function responds with default action +to any that it does get. + +============================================================================*/ + + +LONG FAR PASCAL TrapperWindowEvents IFN4(HWND, hTrapWnd, WORD, message, LONG, wParam, LONG, lParam) +{ +PAINTSTRUCT ps; + +switch(message) + { + case WM_PAINT: + BeginPaint(hTrapWnd,&ps); + EndPaint(hTrapWnd,&ps); + return 0; + } +return(DefWindowProc(hTrapWnd, message, wParam, lParam)); +} +#endif /*HUNTER*/ diff --git a/private/mvdm/softpc.new/host/src/nt_input.c b/private/mvdm/softpc.new/host/src/nt_input.c new file mode 100644 index 000000000..3b89d83d3 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_input.c @@ -0,0 +1,128 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Win32 Input Module. + * + * Description : This module contains data and functions to + * implement the SoftPC keyboard/mouse input subsystem. + * + * Author : D.A.Bartlett (based on X_input.c) + * + * Notes : HELP!!!!!! + * Mods : Tim May 28, 92. Yoda break now on F11 if set YODA=1. + */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <ntddkbd.h> + +#include "insignia.h" +#include "host_def.h" +#include "xt.h" +#include "keyboard.h" +#include "keyba.h" +#include "ica.h" +#include "error.h" +#include "config.h" +#include "keyba.h" +#include "gmi.h" +#include "nt_uis.h" +#include "sas.h" +#include <stdio.h> +#include "trace.h" +#include "video.h" +#include "debug.h" +#include "nt_event.h" +#include "nt_reset.h" +#include "bios.h" +#include CpuH + +#include "host.h" +#include "host_hfx.h" +#include "host_nls.h" +#include "spcfile.h" + + +// The command bits for the kbd light (same as real hardware) +#define CAPS_LOCK 0x04 +#define NUM_LOCK 0x02 +#define SCROLL_LOCK 0x01 + +// functions available thru the keyb functions table +void nt_kb_prepare(void) {} + + +#if NOTUSEDNOTUSED +void nt_kb_light_off IFN1(half_word, kyLight) {} +void nt_kb_restore(void) {} +#endif + +void nt_kb_light_on(UCHAR); +void nt_kb_init(void); +void nt_kb_shutdown(void); + + +// the keyb functions table +KEYBDFUNCS nt_keybd_funcs = {nt_kb_prepare, // not implemented + nt_kb_prepare, // not implemented + nt_kb_prepare, // not implemented + nt_kb_prepare, // not implemented + nt_kb_light_on, + nt_kb_light_on // not implemented + }; + + +/* + * nt_kb_light_on + * + * This code gets called whenever kbdhdw tries to change the kbd leds. + * We cannot allow changes to the real leds because this would get us + * out of sync with user32 physical keyboard state. So what we do is + * to send fake keys to the kbd hdw to reset the state to what the + * the latest state is according to the console input + * + * Caller should hold the kbd mutex + */ +void nt_kb_light_on (unsigned char kyLight) +{ + DWORD KeyState; + unsigned char ChangeBits; + + ChangeBits = kyLight >> 4; + + KeyState = (ToggleKeyState & ~(CAPSLOCK_ON | NUMLOCK_ON | SCROLLLOCK_ON)); + + if(ChangeBits & CAPS_LOCK) { + if (kyLight & CAPS_LOCK) + KeyState |= CAPSLOCK_ON; + } + else { + KeyState |= ToggleKeyState & CAPSLOCK_ON; + } + + if(ChangeBits & NUM_LOCK) { + if(kyLight & NUM_LOCK) + KeyState |= NUMLOCK_ON; + } + else { + KeyState |= ToggleKeyState & NUMLOCK_ON; + } + + + if(ChangeBits & SCROLL_LOCK) { + if(kyLight & SCROLL_LOCK) + KeyState |= SCROLLLOCK_ON; + } + else { + KeyState |= ToggleKeyState & SCROLLLOCK_ON; + } + + if (ToggleKeyState != KeyState) { + SyncToggleKeys( 0, KeyState); + } + +} diff --git a/private/mvdm/softpc.new/host/src/nt_inthk.c b/private/mvdm/softpc.new/host/src/nt_inthk.c new file mode 100644 index 000000000..a6e723212 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_inthk.c @@ -0,0 +1,249 @@ +/*[ + * + * Name: nt_inthk.c + * + * Derived From: (original) + * + * Author: Dave Bartlett + * + * Created On: 11 Jan 1995 + * + * Coding Stds: 2.4 + * + * Purpose: This module implements the memory management functions + * required for 486 NT. + * + * Include File: nt_inthk.h + * + * Copyright Insignia Solutions Ltd., 1994. All rights reserved. + * +]*/ + + +#ifdef CPU_40_STYLE + +/* Need all of the following to include nt.h and windows.h in the same file. */ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "insignia.h" +#include "host_def.h" + +#include "gdpvar.h" +#include "nt_inthk.h" +#include "debug.h" + +/* Make local symbols visible if debugging. */ +#ifndef PROD +#define LOCAL +#endif /* not PROD */ + +/* Macros and typedefs. */ + + +/* Hardware interrupt handler */ +LOCAL BOOL (*HWIntHandler)(ULONG) = NULL; + +#if defined(CCPU) || !defined(PROD) +/* Software interrupt handler */ +LOCAL BOOL (*SWIntHandler)(ULONG) = NULL; + +/* Exception interrupt handler */ +LOCAL BOOL (*EXIntHandler)(ULONG,ULONG) = NULL; + +#endif /* CCPU */ + +/* Global Functions. */ + +/*( +============================= host_hwint_hook ================================= +PURPOSE: + This function is called from the ICA during the process of ACKing an + hardware interrupt. This function will call a hardware interrupt handler + if one is defined. + +INPUT: + Interrupt vector number generated from hardware interrupt +OUTPUT: + Return value - TRUE hardware interrupt processed + FALSE process hardware interrupt in normal way +================================================================================ +)*/ + + +#if defined(CCPU) || !defined(PROD) +GLOBAL BOOL host_hwint_hook IFN1(IS32, int_no) +{ + BOOL returnStatus = FALSE; + + /* hardware interrupt handler defined ? */ + if(HWIntHandler) + { + returnStatus = (HWIntHandler)((ULONG) int_no); + +#ifndef PROD + if(!returnStatus) + always_trace0("Hardware interrupt handler failed"); + +#endif /* PROD */ + } + + return( returnStatus ); +} +#endif + +/*( +======================= VdmInstallHardwareIntHandler =========================== +PURPOSE: + Register a hardware interrupt handler called before the CPU dispatches + the interrupt. + +INPUT: + Hardware interrupt handler function + +OUTPUT: + Return value - NTSTATUS + +================================================================================ +)*/ + +GLOBAL NTSTATUS VdmInstallHardwareIntHandler IFN1(PVOID, HardwareIntHandler) +{ +#ifdef CCPU + HWIntHandler = HardwareIntHandler; +#else + GLOBAL_VDM_HwIntHandler = HardwareIntHandler; +#endif + return(STATUS_SUCCESS); +} + +/*( +============================= host_swint_hook ================================= +PURPOSE: + This function is called from the CCPU prior to provessing a software + interrupt. This function will call a software interrupt handler + if one is defined. + +INPUT: + Interrupt number +OUTPUT: + Return value - TRUE software interrupt processed + FALSE process software interrupt in normal way + +================================================================================ +)*/ + + +#if defined(CCPU) || !defined(PROD) +GLOBAL BOOL host_swint_hook IFN1(IS32, int_no) +{ + BOOL returnStatus = FALSE; + + /* software interrupt handler defined ? */ + if(SWIntHandler) + { + returnStatus = (SWIntHandler)((ULONG) int_no); + +#ifndef PROD + + if(!returnStatus) + always_trace0("Software interrupt handler failed"); + +#endif /* PROD */ + } + + return( returnStatus ); +} +#endif /* CCPU */ + +/*( +======================= VdmInstallSoftwareIntHandler =========================== +PURPOSE: + Register a software interrupt handler called before the CPU dispatches + the software interrupt. + +INPUT: + Software interrupt handler function + +OUTPUT: + Return value - NTSTATUS +================================================================================ +)*/ + +GLOBAL NTSTATUS VdmInstallSoftwareIntHandler IFN1(PVOID, SoftwareIntHandler) +{ +#ifdef CCPU + SWIntHandler = SoftwareIntHandler; +#else + GLOBAL_VDM_SoftIntHandler = SoftwareIntHandler; +#endif + return(STATUS_SUCCESS); +} + +/*( +============================= host_exint_hook ================================= +PURPOSE: + This function is called from the CPU prior to processing a CPU + exception interrupt. This function will call a exception interrupt + handler if one is defined. + +INPUT: + Exception number + Exception error code +OUTPUT: + Return value - TRUE hardware interrupt processed + FALSE process hardware interrupt in normal way + +================================================================================ +)*/ + + +#if defined(CCPU) || !defined(PROD) +GLOBAL BOOL host_exint_hook IFN2(IS32, exp_no, IS32, error_code) +{ + BOOL returnStatus = FALSE; + + /* exception interrupt handler defined ? */ + if(EXIntHandler) + { + returnStatus = (EXIntHandler)((ULONG) exp_no, (ULONG) error_code); + +#ifndef PROD + + if(!returnStatus) + always_trace0("Exception interrupt handler failed (%x)"); + +#endif /* PROD */ + } + + return( returnStatus ); +} +#endif /* CCPU */ + +/*( +======================= VdmInstallFaultHandler =========================== +PURPOSE: + Register a CPU exception interrupt handler called before the CPU + dispatches the exceptioninterrupt. + +INPUT: + Exception interrupt handler function + +OUTPUT: + Return value - NTSTATUS +================================================================================ +)*/ + +GLOBAL NTSTATUS VdmInstallFaultHandler IFN1(PVOID, FaultHandler) +{ +#ifdef CCPU + EXIntHandler = FaultHandler; +#else + GLOBAL_VDM_FaultHandler = FaultHandler; +#endif + return(STATUS_SUCCESS); +} + +#endif /* CPU_40_STYLE */ diff --git a/private/mvdm/softpc.new/host/src/nt_keycd.c b/private/mvdm/softpc.new/host/src/nt_keycd.c new file mode 100644 index 000000000..2d1f80423 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_keycd.c @@ -0,0 +1,605 @@ +/*************************************************************************** + * * + * MODULE : nt_keycd.c * + * * + * PURPOSE : Convert a windows key message to a PC keyboard number * + * * + * FUNCTIONS : KeyMsgToKeyCode() * + * * + ****************************************************************************/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> + +#include "windows.h" + +// +// OEM Scancode to (ie Scancode set 1) to keynum table. +// Somehow this has to end up being loaded rather than compiled in... +// +#define UNDEFINED 0 + +/*@ACW======================================================================= + +Microsoft now use scan code set 1 as their base scan code set. This means that +we had to change ours also. Not only that, two tables are needed now: one to +hold the regular keyset, the other to hold the ENHANCED key options. Scan code +set 1 differs to scan code set 3 in that some scan codes are the same for +different keystrokes. So when an enhanced bit is set in the KEY_EVENT_RECORD. +dwControlKeyState, a second (very sparse) table is substituted for the regular +one. +A small, teensy, weensy detail... All the key numbers are mapped to different +scancode values for the regular keys just to make life a little more fun! + +============================================================================*/ + +BYTE Scan1ToKeynum[] = +{ + // Keynum Scancode US encoding + + + UNDEFINED, // 0x0 + 110, // 0x1 Escape + 2, // 0x2 1 ! + 3, // 0x3 2 @ + 4, // 0x4 3 # + 5, // 0x5 4 $ + 6, // 0x6 5 % + 7, // 0x7 6 ^ + 8, // 0x8 7 & + 9, // 0x9 8 * + 10, // 0xa 9 ( + 11, // 0xb 0 ) + 12, // 0xc - _ + 13, // 0xd = + + 15, // 0xe Backspace + 16, // 0xf Tab + 17, // 0x10 q Q + 18, // 0x11 w W + 19, // 0x12 e E + 20, // 0x13 r R + 21, // 0x14 t T + 22, // 0x15 y Y + 23, // 0x16 u U + 24, // 0x17 i I + 25, // 0x18 o O + 26, // 0x19 p P + 27, // 0x1a [ { + 28, // 0x1b ] } + 43, // 0x1c Enter + 58, // 0x1d Left Control + 31, // 0x1e a A + 32, // 0x1f s S + 33, // 0x20 d D + 34, // 0x21 f F + 35, // 0x22 g G + 36, // 0x23 h H + 37, // 0x24 j J + 38, // 0x25 k K + 39, // 0x26 l L + 40, // 0x27 ; : + 41, // 0x28 ' " + 1, // 0x29 ` ~ + 44, // 0x2a Left Shift + 42, // 0x2b \ | or International Key UK = ~ # + 46, // 0x2c z Z + 47, // 0x2d x X + 48, // 0x2e c C + 49, // 0x2f v V + 50, // 0x30 b B + 51, // 0x31 n N + 52, // 0x32 m M + 53, // 0x33 , < + 54, // 0x34 . > + 55, // 0x35 / ? + 57, // 0x36 Right Shift (see extended table) + 100, // 0x37 Keypad * + 60, // 0x38 Left Alt + 61, // 0x39 Space + 30, // 0x3a Caps Lock + 112, // 0x3b F1 + 113, // 0x3c F2 + 114, // 0x3d F3 + 115, // 0x3e F4 + 116, // 0x3f F5 + 117, // 0x40 F6 + 118, // 0x41 F7 + 119, // 0x42 F8 + 120, // 0x43 F9 + 121, // 0x44 F10 + 126, // 0x45 Break Key + 125, // 0x46 Scroll Lock + 91, // 0x47 Keypad Home 7 + 96, // 0x48 Keypad Up 8 + 101, // 0x49 Keypad Pg Up + 105, // 0x4a Keypad - + 92, // 0x4b Keypad Left 4 + 97, // 0x4c Keypad 5 + 102, // 0x4d Keypad Right 6 + 106, // 0x4e Keypad + + 93, // 0x4f Keypad End 1 + 98, // 0x50 Keypad Down 2 + 103, // 0x51 Keypad Pg Down 3 + 99, // 0x52 Keypad Ins 0 + 104, // 0x53 Keypad Del . + UNDEFINED, // 0x54 + UNDEFINED, // 0x55 + 45, // 0x56 International Key UK = \ | + 122, // 0x57 F11 + 123, // 0x58 F12 + UNDEFINED, // 0x59 + UNDEFINED, // 0x5a + UNDEFINED, // 0x5b + UNDEFINED, // 0x5c + UNDEFINED, // 0x5d + UNDEFINED, // 0x5e + UNDEFINED, // 0x5f + UNDEFINED, // 0x60 + UNDEFINED, // 0x61 + UNDEFINED, // 0x62 + UNDEFINED, // 0x63 + UNDEFINED, // 0x64 + UNDEFINED, // 0x65 + UNDEFINED, // 0x66 + UNDEFINED, // 0x67 + UNDEFINED, // 0x68 + UNDEFINED, // 0x69 + UNDEFINED, // 0x6a + UNDEFINED, // 0x6b + UNDEFINED, // 0x6c + UNDEFINED, // 0x6d + UNDEFINED, // 0x6e + UNDEFINED, // 0x6f + UNDEFINED, // 0x70 + UNDEFINED, // 0x71 + UNDEFINED, // 0x72 + 56, // 0x73 Brazilian ABNT / ? + UNDEFINED, // 0x74 + UNDEFINED, // 0x75 + UNDEFINED, // 0x76 + UNDEFINED, // 0x77 + UNDEFINED, // 0x78 + UNDEFINED, // 0x79 + UNDEFINED, // 0x7a + UNDEFINED, // 0x7b + 94, // 0x7c Extended kbd (IBM 122 key) + 14, // 0x7d Extended kbd (IBM 122 key) + 107, // 0x7e Brazilian ABNT numpad . + UNDEFINED, // 0x7f + UNDEFINED, // 0x80 + UNDEFINED, // 0x81 + UNDEFINED, // 0x82 + UNDEFINED, // 0x83 + UNDEFINED // 0x84 +}; + +/*@ACW==================================================================== + +Note that in the following extended keyboard table, the shift key values +have also been given an entry because these keys can be used as modifiers +for the other extended keys. + +========================================================================*/ + + +BYTE Scan1ToKeynumExtended[] = +{ + // Keynum Scancode US encoding + + 31, // 0x0 + UNDEFINED, // 0x1 + UNDEFINED, // 0x2 + UNDEFINED, // 0x3 + UNDEFINED, // 0x4 + UNDEFINED, // 0x5 + UNDEFINED, // 0x6 + UNDEFINED, // 0x7 + UNDEFINED, // 0x8 + UNDEFINED, // 0x9 + UNDEFINED, // 0xa + UNDEFINED, // 0xb + UNDEFINED, // 0xc + UNDEFINED, // 0xd + UNDEFINED, // 0xe + UNDEFINED, // 0xf + UNDEFINED, // 0x10 + UNDEFINED, // 0x11 + UNDEFINED, // 0x12 + UNDEFINED, // 0x13 + UNDEFINED, // 0x14 + UNDEFINED, // 0x15 + UNDEFINED, // 0x16 + UNDEFINED, // 0x17 + UNDEFINED, // 0x18 + UNDEFINED, // 0x19 + UNDEFINED, // 0x1a + UNDEFINED, // 0x1b + 108, // 0x1c Extended 1c Num Enter + 64, // 0x1d Extended 1d Right Ctrl + UNDEFINED, // 0x1e + UNDEFINED, // 0x1f + UNDEFINED, // 0x20 + UNDEFINED, // 0x21 + UNDEFINED, // 0x22 + UNDEFINED, // 0x23 + UNDEFINED, // 0x24 + UNDEFINED, // 0x25 + UNDEFINED, // 0x26 + UNDEFINED, // 0x27 + UNDEFINED, // 0x28 + UNDEFINED, // 0x29 + 44, // 0x2a Extended 2a left shift + UNDEFINED, // 0x2b + UNDEFINED, // 0x2c + UNDEFINED, // 0x2d + UNDEFINED, // 0x2e + UNDEFINED, // 0x2f + UNDEFINED, // 0x30 + UNDEFINED, // 0x31 + UNDEFINED, // 0x32 + UNDEFINED, // 0x33 + UNDEFINED, // 0x34 + 95, // 0x35 Extended 35 keypad / + 57, // 0x36 Extended 36 right shift + 124, // 0x37 PrintScreen + 62, // 0x38 Extended 38 right alt + UNDEFINED, // 0x39 + UNDEFINED, // 0x3a + UNDEFINED, // 0x3b + UNDEFINED, // 0x3c + UNDEFINED, // 0x3d + UNDEFINED, // 0x3e + UNDEFINED, // 0x3f + UNDEFINED, // 0x40 + UNDEFINED, // 0x41 + UNDEFINED, // 0x42 + UNDEFINED, // 0x43 + UNDEFINED, // 0x44 + 90, // 0x45 Num Lock + 126, // 0x46 + 80, // 0x47 Extended 47 Home + 83, // 0x48 Extended 48 Up + 85, // 0x49 Extended 49 Page up + UNDEFINED, // 0x4a + 79, // 0x4b Extended 4b Left + UNDEFINED, // 0x4c + 89, // 0x4d Extended 4d Right + UNDEFINED, // 0x4e + 81, // 0x4f Extended 4f End + 84, // 0x50 Extended 50 Down + 86, // 0x51 Extended 51 Page Down + 75, // 0x52 Extended 52 Insert + 76, // 0x53 Extended 53 Delete + +}; + + + +/* + * Table for translating BiosBuffer scan codes with special + * NULL ascii chars, and their associated control flags + * If it is not in this table The Bios scan code should + * be the same as the win32 Scan code. + */ +#define FIRST_NULLCHARSCAN 0x54 +#define LAST_NULLCHARSCAN 0xa6 + +typedef struct _NullAsciiCharScan { + WORD wWinSCode; + DWORD dwControlState; +} NULLCHARSCAN; + +NULLCHARSCAN aNullCharScan[] = +{ +// WinSCode dwControlState BiosSCode Keys + + 0x3b, SHIFT_PRESSED, // 0x54 Shift+F1 + 0x3c, SHIFT_PRESSED, // 0x55 Shift+F2 + 0x3d, SHIFT_PRESSED, // 0x56 Shift+F3 + 0x3e, SHIFT_PRESSED, // 0x57 Shift+F4 + 0x3f, SHIFT_PRESSED, // 0x58 Shift+F5 + 0x40, SHIFT_PRESSED, // 0x59 Shift+F6 + 0x41, SHIFT_PRESSED, // 0x5a Shift+F7 + 0x42, SHIFT_PRESSED, // 0x5b Shift+F8 + 0x43, SHIFT_PRESSED, // 0x5c Shift+F9 + 0x44, SHIFT_PRESSED, // 0x5d Shift+F10 + 0x3b, LEFT_CTRL_PRESSED, // 0x5e Ctrl+F1 + 0x3c, LEFT_CTRL_PRESSED, // 0x5f Ctrl+F2 + 0x3d, LEFT_CTRL_PRESSED, // 0x60 Ctrl+F3 + 0x3e, LEFT_CTRL_PRESSED, // 0x61 Ctrl+F4 + 0x3f, LEFT_CTRL_PRESSED, // 0x62 Ctrl+F5 + 0x40, LEFT_CTRL_PRESSED, // 0x63 Ctrl+F6 + 0x41, LEFT_CTRL_PRESSED, // 0x64 Ctrl+F7 + 0x42, LEFT_CTRL_PRESSED, // 0x65 Ctrl+F8 + 0x43, LEFT_CTRL_PRESSED, // 0x66 Ctrl+F9 + 0x44, LEFT_CTRL_PRESSED, // 0x67 Ctrl+F10 + 0x3b, LEFT_ALT_PRESSED, // 0x68 Alt+F1 + 0x3c, LEFT_ALT_PRESSED, // 0x69 Alt+F2 + 0x3d, LEFT_ALT_PRESSED, // 0x6a Alt+F3 + 0x3e, LEFT_ALT_PRESSED, // 0x6b Alt+F4 + 0x3f, LEFT_ALT_PRESSED, // 0x6c Alt+F5 + 0x40, LEFT_ALT_PRESSED, // 0x6d Alt+F6 + 0x41, LEFT_ALT_PRESSED, // 0x6e Alt+F7 + 0x42, LEFT_ALT_PRESSED, // 0x6f Alt+F8 + 0x43, LEFT_ALT_PRESSED, // 0x70 Alt+F9 + 0x44, LEFT_ALT_PRESSED, // 0x71 Alt+F10 + 0, 0, // 0x72 Ctrl+PrtSc + 0x4b, LEFT_CTRL_PRESSED, // 0x73 Ctrl+Left + 0x4d, LEFT_CTRL_PRESSED, // 0x74 Ctrl+Right + 0x4f, LEFT_CTRL_PRESSED, // 0x75 Ctrl+End + 0x51, LEFT_CTRL_PRESSED, // 0x76 Ctrl+PgDn + 0x47, LEFT_CTRL_PRESSED, // 0x77 Ctrl+Home + 0x2, LEFT_ALT_PRESSED, // 0x78 Alt+1 + 0x3, LEFT_ALT_PRESSED, // 0x79 Alt+2 + 0x4, LEFT_ALT_PRESSED, // 0x7a Alt+3 + 0x5, LEFT_ALT_PRESSED, // 0x7b Alt+4 + 0x6, LEFT_ALT_PRESSED, // 0x7c Alt+5 + 0x7, LEFT_ALT_PRESSED, // 0x7d Alt+6 + 0x8, LEFT_ALT_PRESSED, // 0x7e Alt+7 + 0x9, LEFT_ALT_PRESSED, // 0x7f Alt+8 + 0xa, LEFT_ALT_PRESSED, // 0x80 Alt+9 + 0xb, LEFT_ALT_PRESSED, // 0x81 Alt+0 + 0xc, LEFT_ALT_PRESSED, // 0x82 Alt+- + 0xd, LEFT_ALT_PRESSED, // 0x83 Alt+= + 0x49, LEFT_CTRL_PRESSED, // 0x84 Ctrl+PgUp + 0, 0, // 0x85 ????? + 0, 0, // 0x86 ????? + 0x85, SHIFT_PRESSED, // 0x87 Shift+F11 + 0x86, SHIFT_PRESSED, // 0x88 Shift+F12 + 0x85, LEFT_CTRL_PRESSED, // 0x89 Ctrl+F11 + 0x86, LEFT_CTRL_PRESSED, // 0x8a Ctrl+F12 + 0x85, LEFT_ALT_PRESSED, // 0x8b Alt+F11 + 0x86, LEFT_ALT_PRESSED, // 0x8c Alt+F12 + 0x48, LEFT_CTRL_PRESSED, // 0x8d Ctrl+Up + 0x4a, LEFT_CTRL_PRESSED, // 0x8e Ctrl+- + 0x4c, LEFT_CTRL_PRESSED, // 0x8f Ctrl+5 + 0x4e, LEFT_CTRL_PRESSED, // 0x90 Ctrl++ + 0x50, LEFT_CTRL_PRESSED, // 0x91 Ctrl+Down + 0x52, LEFT_CTRL_PRESSED, // 0x92 Ctrl+Ins + 0x53, LEFT_CTRL_PRESSED, // 0x93 Ctrl+Del + 0, 0, // 0x94 ????? + 0, 0, // 0x95 ????? + 0, 0, // 0x96 ????? + 0x47, LEFT_ALT_PRESSED, // 0x97 Alt+Home + 0x48, LEFT_ALT_PRESSED, // 0x98 Alt+Up + 0x49, LEFT_ALT_PRESSED, // 0x99 Alt+PgUp + 0, 0, // 0x9a ????? + 0x4b, LEFT_ALT_PRESSED, // 0x9b Alt+Left + 0, 0, // 0x9c ????? + 0x4d, LEFT_ALT_PRESSED, // 0x9d Alt+Right + 0, 0, // 0x9e ????? + 0x4f, LEFT_ALT_PRESSED, // 0x9f Alt+End + 0x50, LEFT_ALT_PRESSED, // 0xa0 Alt+Down + 0x51, LEFT_ALT_PRESSED, // 0xa1 Alt+PgDn + 0x52, LEFT_ALT_PRESSED, // 0xa2 Alt+Ins + 0x53, LEFT_ALT_PRESSED, // 0xa3 Alt+Del + 0, 0, // 0xa4 ????? + 0xf, LEFT_ALT_PRESSED, // 0xa5 Alt+Tab + 0x1c, LEFT_ALT_PRESSED // 0xa6 Alt+Enter +}; + + +WORD aNumPadSCode[] = // index by VK_NUMPAD0 as zero offset +{ + 0x52, // VK_NUMPAD0 - 60 + 0x4f, // VK_NUMPAD1 61 + 0x50, // VK_NUMPAD2 62 + 0x51, // VK_NUMPAD3 63 + 0x4b, // VK_NUMPAD4 64 + 0x4c, // VK_NUMPAD5 65 + 0x4d, // VK_NUMPAD6 66 + 0x47, // VK_NUMPAD7 67 + 0x48, // VK_NUMPAD8 68 + 0x49 // VK_NUMPAD9 69 +}; + + + + + + + /**************************************************************************** + * * + * FUNCTIONS : BYTE KeyMsgToKeyCode(WORD vKey, DWORD KeyFlags) * + * * + * PURPOSE : Convert a windows key message to a PC keyboard number * + * Return 0 if not mapped. * + * * + ****************************************************************************/ + +BYTE KeyMsgToKeyCode(PKEY_EVENT_RECORD KeyEvent) +{ + /*:::::::::::::::::::::::::::::::::::: do we need the enhanced key set ? */ + + if(!(KeyEvent->dwControlKeyState & ENHANCED_KEY)) + { + + /*............................... the regular keyset is what we need */ + + return KeyEvent->wVirtualScanCode > sizeof(Scan1ToKeynum) + ? 0 + : Scan1ToKeynum[KeyEvent->wVirtualScanCode]; + } + else + { + /*.................................. we do need the extended key set */ + + + return KeyEvent->wVirtualScanCode > sizeof(Scan1ToKeynumExtended) + ? 0 + : Scan1ToKeynumExtended[KeyEvent->wVirtualScanCode]; + } +} + + + + + +/* BiosKeyToInputRecord + * + * Translates Bios Buffer Keys to win32 console type of key_events. + * + * entry: pKeyEvent - addr of KEY_EVENT structure + * pKeyEvent->uChar.AsciiChar - Bios Buffer character + * pKeyEvent->wVirtualScanCode - Bios Buffer scan code + * + * exit: all KEY_EVENT fields are filled in. + * The AsciiChar has been converted to unicode + * + * If a character is not in the current keyboard layout + * we return TRUE with: dwControlKeyState |= NUMLOCK_ON; + * wVirtualKeyCode = VK_MENU; + * wVirtualScanCode = 0x38; + * OemChar (not unicode) + */ +BOOL BiosKeyToInputRecord(PKEY_EVENT_RECORD pKeyEvent) +{ + USHORT KeyState; + NTSTATUS Status; + UCHAR AsciiChar=(UCHAR)pKeyEvent->uChar.AsciiChar; + WCHAR UnicodeChar; + + pKeyEvent->wRepeatCount = 1; + pKeyEvent->wVirtualKeyCode = 0; + pKeyEvent->dwControlKeyState = 0; + + // we treat 0xF0 Ascii Char as NULL char just like the bios + if (AsciiChar == 0xF0 && pKeyEvent->wVirtualScanCode) { + AsciiChar = 0; + } + + + // convert oem char to unicode character, cause we can do it more + // efficiently than console (already going thru char by char). + Status = RtlOemToUnicodeN(&UnicodeChar, + sizeof(WCHAR), + NULL, + &AsciiChar, + 1 ); + if (!NT_SUCCESS(Status)) { + return FALSE; + } + + + + // Convert BiosBuffer ScanCode for NULL asciiChars to + // windows scan code + if ( (!AsciiChar) && + pKeyEvent->wVirtualScanCode >= FIRST_NULLCHARSCAN && + pKeyEvent->wVirtualScanCode <= LAST_NULLCHARSCAN ) + { + pKeyEvent->wVirtualScanCode -= FIRST_NULLCHARSCAN; + pKeyEvent->dwControlKeyState = aNullCharScan[pKeyEvent->wVirtualScanCode].dwControlState; + pKeyEvent->wVirtualScanCode = aNullCharScan[pKeyEvent->wVirtualScanCode].wWinSCode; + } + + + // Some CTRL-Extended keys have special bios scan codes + // These scan codes are not recognized by windows. Change + // to a windows compatible scan code, and set CTRL flag + else if (AsciiChar == 0xE0 && pKeyEvent->wVirtualScanCode) { + pKeyEvent->dwControlKeyState = ENHANCED_KEY; + if (AsciiChar == 0xE0) { + pKeyEvent->dwControlKeyState |= LEFT_CTRL_PRESSED; + switch (pKeyEvent->wVirtualScanCode) { + case 0x73: pKeyEvent->wVirtualScanCode = 0x4B; + break; + case 0x74: pKeyEvent->wVirtualScanCode = 0x4D; + break; + case 0x75: pKeyEvent->wVirtualScanCode = 0x4f; + break; + case 0x76: pKeyEvent->wVirtualScanCode = 0x51; + break; + case 0x77: pKeyEvent->wVirtualScanCode = 0x47; + break; + case 0x84: pKeyEvent->wVirtualScanCode = 0x49; + break; + case 0x8D: pKeyEvent->wVirtualScanCode = 0x48; + break; + case 0x91: pKeyEvent->wVirtualScanCode = 0x50; + break; + case 0x92: pKeyEvent->wVirtualScanCode = 0x52; + break; + case 0x93: pKeyEvent->wVirtualScanCode = 0x53; + break; + + default: // the rest should have correct scan codes + // but not CTRL bit + pKeyEvent->dwControlKeyState &= ~LEFT_CTRL_PRESSED; + } + } + + AsciiChar = 0; + UnicodeChar = 0; + } + + + // The keypad "/" and the keypad "enter" special cases + + else if (pKeyEvent->wVirtualScanCode == 0xE0) { + pKeyEvent->dwControlKeyState = ENHANCED_KEY; + if (AsciiChar == 0x2f) { // is keypad "/" + pKeyEvent->wVirtualScanCode = 0x35; + pKeyEvent->wVirtualKeyCode = VK_DIVIDE; + } + else { // is keypad enter chars == 0xd, 0xa + pKeyEvent->wVirtualScanCode = 0x1C; + pKeyEvent->wVirtualKeyCode = VK_RETURN; + if (AsciiChar == 0xA) { + pKeyEvent->dwControlKeyState |= LEFT_CTRL_PRESSED; + } + } + } + + + + // get control flags\VirtualKey for normal ascii characters, + + else if (AsciiChar && + pKeyEvent->wVirtualScanCode != 0x01 && // ESC + pKeyEvent->wVirtualScanCode != 0x0E && // Backspace + pKeyEvent->wVirtualScanCode != 0x0F && // Tab + pKeyEvent->wVirtualScanCode != 0x1C ) // Enter + { + + KeyState = (USHORT) VkKeyScanW(UnicodeChar); + + if (KeyState == 0xFFFF) { + /* fail means not a physical key (ALT-NUMPAD entry sequence) + * Proper emeulation requires that we generate it by doing + * ALT-NUMLOCK-xxx-NUMLOCK-ALT. + * We shortcut this by sending console, the final key event. + * hoping that apps won't notice the difference. + */ + pKeyEvent->wVirtualScanCode = 0; + pKeyEvent->wVirtualKeyCode = VK_MENU; // dummy opt + } + else { + pKeyEvent->wVirtualKeyCode = (WORD)LOBYTE(KeyState); + if (KeyState & 0x100) + pKeyEvent->dwControlKeyState |= SHIFT_PRESSED; + if (KeyState & 0x200) + pKeyEvent->dwControlKeyState |= LEFT_CTRL_PRESSED; + if (KeyState & 0x400) + pKeyEvent->dwControlKeyState |= LEFT_ALT_PRESSED; + + // some keys get mapped to different scan codes (NUMPAD) + // so get matching scan code + pKeyEvent->wVirtualScanCode = MapVirtualKey(pKeyEvent->wVirtualKeyCode,0); + } + } + + + // Get a Virtual KeyCode, if we don't have one yet + if (!pKeyEvent->wVirtualKeyCode) { + pKeyEvent->wVirtualKeyCode = MapVirtualKey(pKeyEvent->wVirtualScanCode,3); + if (!pKeyEvent->wVirtualKeyCode) { + return FALSE; + } + } + + pKeyEvent->uChar.UnicodeChar = UnicodeChar; + + + return TRUE; +} diff --git a/private/mvdm/softpc.new/host/src/nt_lpt.c b/private/mvdm/softpc.new/host/src/nt_lpt.c new file mode 100644 index 000000000..083ca7586 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_lpt.c @@ -0,0 +1,698 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntddvdm.h> +#include <windows.h> +#include "insignia.h" +#include "host_def.h" +#include <malloc.h> + + +/* + * Name: nt_lpt.c + * Derived From: Sun 2.0 sun4_lpt.c + * Author: D A Bartlett + * Created On: + * Purpose: NT specific parallel port functions + * + * (c)Copyright Insignia Solutions Ltd., 1991. All rights reserved. + * + + * Note. This port is unlike most ports because the config system has been + * removed. It was the job of the config system to validate and open the + * printer ports. The only calls to the host printer system are now + * make from printer.c. and consist of the following calls. + * + * + * 1) host_print_byte + * 2) host_print_auto_feed + * 3) host_print_doc + * 4) host_lpt_status + * + * + * On the Microsoft model the printer ports will be opened when they are + * written to. + * + * Modifications: + * + * Tim June 92. Amateur attempt at buffered output to speed things up. + * + */ + + +/* + + +Work outstanding on this module, + +1) Check the usage of port_state +2) Check error handling in write function +3) host_print_doc() always flushs the port, is this correct ? +4) host_print_auto_feed - what should this function do ? +5) Error handling in host_printer_open(), UIF needed ? + +*/ + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#ifdef PRINTER + +/* SoftPC include files */ +#include "xt.h" +#include "error.h" +#include "config.h" +#include "timer.h" +#include "host_lpt.h" +#include "hostsync.h" +#include "host_rrr.h" +#include "gfi.h" +#include "debug.h" +#include "idetect.h" +#include "sas.h" +#include "printer.h" +#ifndef PROD +#include "trace.h" +#endif + +boolean flushBuffer IFN1(int, adapter); +#ifdef MONITOR +extern BOOLEAN MonitorInitializePrinterInfo(WORD, PWORD, PUCHAR, PUCHAR, PUCHAR, PUCHAR); +extern BOOLEAN MonitorEnablePrinterDirectAccess(WORD, HANDLE, BOOLEAN); +extern BOOLEAN MonitorPrinterWriteData(WORD Adapter, BYTE Value); + +extern sys_addr lp16BitPrtBuf; +extern sys_addr lp16BitPrtCount; +extern sys_addr lp16BitPrtId; +boolean host_print_buffer(int adapter); +#endif + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Macros ::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +#ifdef MONITOR + +sys_addr lpt_status_addr; + +#define get_lpt_status(adap) \ + (sas_hw_at_no_check(lpt_status_addr+(adap))) +#define set_lpt_status(adap,val) \ + (sas_store_no_check(lpt_status_addr+(adap), (val))) + +#else /* MONITOR */ + +#define get_lpt_status(adap) (host_lpt[(adap)].port_status) +#define set_lpt_status(adap,val) (host_lpt[(adap)].port_status = (val)) + +#endif /* MONITOR */ + +#define KBUFFER_SIZE 1024 // Buffering macros +#define HIGH_WATER 1020 +#define DIRECT_ACCESS_HIGH_WATER 1020 + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Structure for host specific state data ::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +typedef struct +{ + ULONG port_status; // Port status + HANDLE handle; // Printer handle + int inactive_counter; // Inactivate counter + int inactive_trigger; // When equal to inactive_counter close port + int bytesInBuffer; // current size of buffer + int flushThreshold; // + DWORD FileType; // DISK, CHAR, PIPE etc. + BOOLEAN active; // Printer open and active + BOOLEAN dos_opened; // printer opened with DOS open + byte *kBuffer; // output buffer + BOOLEAN direct_access; + BOOLEAN no_device_attached; +} HOST_LPT; + +HOST_LPT host_lpt[NUM_PARALLEL_PORTS]; + +#ifdef MONITOR + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::: On x86 machines the host_lpt_status table is kept on the 16-bit ::::*/ +/*:::: side in order to reduce the number of expensive BOPs. Here we ::::*/ +/*:::: are passed the address of the table. ::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL void host_printer_setup_table(sys_addr table_addr, word nPorts, word * portAddr) +{ + lpt_status_addr = table_addr + 3 * NUM_PARALLEL_PORTS; + // Now fill in the TIB entries for printer_info + MonitorInitializePrinterInfo (nPorts, + portAddr, + (LPBYTE)(table_addr + NUM_PARALLEL_PORTS), + (LPBYTE)(table_addr + 2 * NUM_PARALLEL_PORTS), + (LPBYTE)(table_addr), + (LPBYTE)(lpt_status_addr) + ); + + +} + +#endif /* MONITOR */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::: Set auto close trigger :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +VOID host_set_inactivate_counter(int adapter) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + int close_in_ms; // Flush rate in milliseconds + + /*::::::::::::::::::::::::::::::::::::::::::::::: Is auto close enabled */ + + + if(!config_inquire(C_AUTOFLUSH, NULL)) + { + lpt->inactive_trigger = 0; /* Disable auto flush */ + return; /* Autoflush not active */ + } + + /*::::::::::::::::::::::::::::::::::::::::::: Calculate closedown count */ + + close_in_ms = ((int) config_inquire(C_AUTOFLUSH_DELAY, NULL)) * 1000; + + lpt->inactive_trigger = close_in_ms / (SYSTEM_TICK_INTV/1000); + + lpt->inactive_counter = 0; //Reset close down counter + lpt->no_device_attached = FALSE; +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::: Open printer :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +SHORT host_lpt_open(int adapter, BOOLEAN direct_access) +{ + DWORD BytesReturn; + + FAST HOST_LPT *lpt = &host_lpt[adapter]; // Adapter control structure + CHAR *lptName; // Adapter filename + + if (!direct_access) + lpt->no_device_attached = FALSE; + else if (lpt->no_device_attached) + return FALSE; + + lpt->bytesInBuffer = 0; // Init output buffer index + + /*::::::::::::::::::::::::::::::::::::::::: Get printer name for Config */ + + /* use a different device name for DONGLE support */ + lptName = (CHAR *) config_inquire((UTINY)((direct_access ? C_VDMLPT1_NAME : + C_LPT1_NAME) + + adapter), NULL); + +#ifndef PROD + fprintf(trace_file, "Opening printer port %s (%d)\n",lptName,adapter); +#endif + + if ((lpt->kBuffer = (byte *)host_malloc (KBUFFER_SIZE)) == NULL) { + // dont put a popup here as the caller of this routine handles it + return(FALSE); + } + lpt->flushThreshold = HIGH_WATER; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::: Open printer */ + + + lpt->direct_access = FALSE; + lpt->active = FALSE; + + lpt->handle = CreateFile(lptName, + GENERIC_WRITE, + direct_access ? 0 : FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + + /*:::::::::::::::::::::::::::::::::::::::::::::::::: Valid open request */ + + if(lpt->handle == (HANDLE) -1) + { + host_free (lpt->kBuffer); + // UIF needed to inform user that the open attempt failed +#ifndef PROD + fprintf(trace_file, "Failed to open printer port\n"); +#endif + if (direct_access && GetLastError() == ERROR_FILE_NOT_FOUND) + lpt->no_device_attached = TRUE; + + return(FALSE); + } + + + /*::::::::::::::::::::::::::::::::::::::Activate port and reset status */ + + lpt->FileType = GetFileType(lpt->handle); + // can not open direct_access access to a redirected device. + if (direct_access && lpt->FileType != FILE_TYPE_CHAR) { + CloseHandle(lpt->handle); + return FALSE; + } + lpt->active = TRUE; + set_lpt_status(adapter, 0); + lpt->direct_access = direct_access; + if (lpt->direct_access) { + lpt->flushThreshold = DIRECT_ACCESS_HIGH_WATER; +#ifdef MONITOR + MonitorEnablePrinterDirectAccess((WORD)adapter, lpt->handle, TRUE); +#endif + } + + /*:::::::::::::::::::::::::::::::::::::::::: Setup auto close counters */ + + host_set_inactivate_counter(adapter); + + return(TRUE); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Close all printer ports ::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +GLOBAL void host_lpt_close_all(void) +{ + FAST HOST_LPT *lpt; + FAST int i; + + /*::::::::::: Scan through printer adapters updating auto flush counters */ + + + for(i=0, lpt = &host_lpt[0]; i < NUM_PARALLEL_PORTS; i++, lpt++) + { + + if(lpt->active) + host_lpt_close(i); /* Close printer port */ + } +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Close printer :::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +VOID host_lpt_close(int adapter) +{ + DWORD BytesReturn; + + FAST HOST_LPT *lpt = &host_lpt[adapter]; + + if (lpt->direct_access) + printer_is_being_closed(adapter); + +#ifdef MONITOR + if (sas_hw_at_no_check(lp16BitPrtId) == adapter){ + host_print_buffer (adapter); + sas_store_no_check(lp16BitPrtId,0xff); + } +#endif + /*::::::::::::::::::::::::::::::::::::::::: Is the printer port active */ + + if(lpt->active) + { + /* + ** Tim June 92. Flush output buffer to get the last output out. + ** If there's an error I think we've got to ignore it. + */ + (void)flushBuffer(adapter); + +#ifndef PROD + fprintf(trace_file, "Closing printer port (%d)\n",adapter); +#endif + +#ifdef MONITOR + if (lpt->direct_access) + MonitorEnablePrinterDirectAccess((WORD)adapter, lpt->handle, FALSE); +#endif + CloseHandle(lpt->handle); /* Close printer port */ + host_free (lpt->kBuffer); + lpt->handle = (HANDLE) -1; /* Mark device as closed */ + + lpt->active = FALSE; /* Deactive printer port */ + set_lpt_status(adapter, 0); /* Reset port status */ + +#ifndef PROD + fprintf(trace_file, "Counter expired, closing LPT%d\n", adapter+1); +#endif + } +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::: Return the status of the lpt channel for an adapter :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL ULONG host_lpt_status(int adapter) +{ + return(get_lpt_status(adapter)); +} + +GLOBAL UCHAR host_read_printer_status_port(int adapter) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + UCHAR PrinterStatus; + DWORD BytesReturn; + + + if(!lpt->active) + { + /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ + + if(!host_lpt_open(adapter, TRUE)) + { +#ifndef PROD + fprintf(trace_file, "file open error %d\n", GetLastError()); +#endif + set_lpt_status(adapter, HOST_LPT_BUSY); + return(FALSE); /* exit, printer not active !!!! */ + } + } + if (lpt->bytesInBuffer) + flushBuffer(adapter); + if (!DeviceIoControl(lpt->handle, + IOCTL_VDM_PAR_READ_STATUS_PORT, + NULL, // no input buffer + 0, + &PrinterStatus, + sizeof(PrinterStatus), + &BytesReturn, + NULL // no overlap + )) { + +#ifndef PROD + fprintf(trace_file, + "host_read_printer_status_port failed, error = %ld\n", + GetLastError() + ); +#endif + PrinterStatus = 0; + } + return(PrinterStatus); +} + +BOOLEAN host_set_lpt_direct_access(int adapter, BOOLEAN direct_access) +{ + DWORD BytesReturn; + + FAST HOST_LPT *lpt = &host_lpt[adapter]; + + host_lpt_close(adapter); + host_lpt_open(adapter, direct_access); + if (!lpt->active) + set_lpt_status(adapter, HOST_LPT_BUSY); + return (lpt->active); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Print a byte ::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* +** Buffer up bytes before they are printed. +** Strategy: +** Save each requested byte in the buffer. +** When the buffer gets full or there's a close request write the +** buffered stuff out. +** Don't forget about errors, eg if the write fails. What about a write +** failure during the close request though? Tough said Tim. +*/ +/* +** flushBuffer() +** Finally write what is in the buffer to the parallel port. It could be a +** real port or a networked printer. +** Input parameter is the parallel port adapter number 0=LPT1 +** Return value of TRUE means write was OK. +*/ +boolean flushBuffer IFN1( int, adapter ) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + DWORD BytesWritten; + + if (lpt->direct_access) { + DeviceIoControl(lpt->handle, + IOCTL_VDM_PAR_WRITE_DATA_PORT, + lpt->kBuffer, + lpt->bytesInBuffer, + NULL, + 0, + &BytesWritten, + NULL + ); + + lpt->bytesInBuffer = 0; + return TRUE; + + } + + + if( !WriteFile( lpt->handle, lpt->kBuffer, + lpt->bytesInBuffer, &BytesWritten, NULL ) + ){ +#ifndef PROD + fprintf(trace_file, "lpt write error %d\n", GetLastError()); +#endif + lpt->bytesInBuffer = 0; + return(FALSE); + }else{ + lpt->bytesInBuffer = 0; + + + /* + * If the print job is being spooled, the spooler can + * take a long time to get started, because of the spoolers + * low priority. This is especially bad for dos apps in which + * idle detection fails or in full screen idle detection is + * inactive. To help push the print job thru the system, + * idle a bit now. + */ + if (lpt->FileType == FILE_TYPE_PIPE) { + Sleep(10); + } + return( TRUE ); + } + +} /* end of flushBuffer() */ + +/* +** Put another byte in to the buffer. If the buffer is full call the +** flush function. +** Return value of TRUE means OK, return FALSE means did a flush and +** it failed. +*/ +boolean toBuffer IFN2( int, adapter, BYTE, b ) +{ + HOST_LPT *lpt = &host_lpt[adapter]; + boolean status = TRUE; + + lpt->kBuffer[lpt->bytesInBuffer++] = b; + + if( lpt->bytesInBuffer >= lpt->flushThreshold ){ + status = flushBuffer( adapter ); + } + return( status ); +} /* end of toBuffer() */ + +GLOBAL BOOL host_print_byte(int adapter, byte value) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + + /*:::::::::::::::::::::::::::::::::::::::::::: Is the printer active ? */ + + if(!lpt->active) + { + /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ + + if(!host_lpt_open(adapter, FALSE)) + { +#ifndef PROD + fprintf(trace_file, "file open error %d\n", GetLastError()); +#endif + set_lpt_status(adapter, HOST_LPT_BUSY); + return(FALSE); /* exit, printer not active !!!! */ + } + } +#if defined(MONITOR) + if (lpt->direct_access) { + MonitorPrinterWriteData((WORD)adapter, value); + } + else +#endif + { + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Send byte to printer */ + + if(toBuffer(adapter, (BYTE) value) == FALSE) + { + set_lpt_status(adapter, HOST_LPT_BUSY); + return(FALSE); + } + } + + /*::::::::::::::::::::::::::: Update idle and activate control variables */ + + lpt->inactive_counter = 0; /* Reset inactivity counter */ + IDLE_comlpt(); /* Tell Idle system there is printer activate */ + + return(TRUE); +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: LPT heart beat call ::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +GLOBAL void host_lpt_heart_beat(void) +{ + FAST HOST_LPT *lpt = &host_lpt[0]; + int i; + + + /*::::::::::: Scan through printer adapters updating auto close counters */ + + + for(i=0; i < NUM_PARALLEL_PORTS; i++, lpt++) + { + + /*:::::::::::::::::::::::::::::::::::::::: Check auto close counters */ + + if(lpt->active && lpt->inactive_trigger && + ++lpt->inactive_counter == lpt->inactive_trigger) + { + host_lpt_close(i); /* Close printer port */ + } + } +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Flush the printer port ::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#if 0 +GLOBAL boolean host_print_doc(int adapter) +{ + if(host_lpt[adapter].active) host_lpt_close(adapter); /* Close printer port */ + + return(TRUE); +} +#endif + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Reset the printer port ::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL void host_reset_print(int adapter) +{ + if(host_lpt[adapter].active) + host_lpt_close(adapter); /* Close printer port */ +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: host_print_auto_feed :::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL void host_print_auto_feed(int adapter, BOOL value) +{ + UNREFERENCED_FORMAL_PARAMETER(adapter); + UNREFERENCED_FORMAL_PARAMETER(value); +} + +#ifdef MONITOR + +GLOBAL boolean host_print_buffer(int adapter) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + word cb; + byte i,ch; + + cb = sas_w_at_no_check(lp16BitPrtCount); + if (!cb) + return (TRUE); + + /*:::::::::::::::::::::::::::::::::::::::::::: Is the printer active ? */ + + if(!lpt->active) + { + /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ + + if(!host_lpt_open(adapter, FALSE)) + { +#ifndef PROD + fprintf(trace_file, "file open error %d\n", GetLastError()); +#endif + set_lpt_status(adapter, HOST_LPT_BUSY); + return(FALSE); /* exit, printer not active !!!! */ + } + } + + if (!lpt->direct_access) { + /*:::::::::::::::::::::::::::::::::::::::::::::::: Send byte to printer */ + + for (i=0; i <cb; i++) { + ch = sas_hw_at_no_check(lp16BitPrtBuf+i); + if(toBuffer(adapter, ch) == FALSE) + { + set_lpt_status(adapter, HOST_LPT_BUSY); + return(FALSE); + } + } + } + else { + // we must no have any int 17 printing data waiting when we + // we in direct access mode + ASSERT(cb == 0); + return FALSE; + } + /*::::::::::::::::::::::::::: Update idle and activate control variables */ + + lpt->inactive_counter = 0; /* Reset inactivity counter */ + IDLE_comlpt(); /* Tell Idle system there is printer activate */ + + return(TRUE); +} +#endif // MONITOR + +GLOBAL void host_lpt_dos_open(int adapter) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + + lpt->dos_opened = TRUE; +} + +GLOBAL void host_lpt_dos_close(int adapter) +{ + FAST HOST_LPT *lpt = &host_lpt[adapter]; + + if (lpt->active) + host_lpt_close(adapter); /* Close printer port */ + lpt->dos_opened = FALSE; +} + +GLOBAL void host_lpt_flush_initialize() +{ + FAST HOST_LPT *lpt; + FAST int i; + + for(i=0, lpt = &host_lpt[0]; i < NUM_PARALLEL_PORTS; i++, lpt++) + lpt->dos_opened = FALSE; + +} + +#endif /* PRINTER */ diff --git a/private/mvdm/softpc.new/host/src/nt_mem.c b/private/mvdm/softpc.new/host/src/nt_mem.c new file mode 100644 index 000000000..73578a04b --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_mem.c @@ -0,0 +1,1456 @@ +/*[ + * + * Name: nt_mem.c + * + * Derived From: (original) + * + * Author: Jerry Sexton + * + * Created On: 7 December 1994 + * + * Coding Stds: 2.4 + * + * Purpose: This module implements the memory management functions + * required for 486 NT. + * + * Include File: nt_mem.h + * + * Copyright Insignia Solutions Ltd., 1994. All rights reserved. + * +]*/ + +#ifdef CPU_40_STYLE + +#if defined(DBG) +#define DEBUG_MEM YES_PLEASE +//#define DEBUG_MEM_DUMP 1 +#endif + +/* Need all of the following to include nt.h and windows.h in the same file. */ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "insignia.h" +#include "host_def.h" + +#include <string.h> +#include <stdlib.h> + +#include "nt_mem.h" +#include "debug.h" +#include "sas.h" + +/* Make local symbols visible if debugging. */ +#ifdef DEBUG_MEM +#define LOCAL + +GLOBAL VOID DumpAllocationHeaders IFN1(); + +#endif /* DEBUG_MEM */ + +/* Macros and typedefs. */ + +/* Entry in header table describing sections of memory. */ +typedef struct _SECTION_HEADER +{ + struct _SECTION_HEADER *prev; /* Previous header in linked list. */ + IU8 flags; /* Is header valid/allocated? */ + IU8 *address; /* Address of corresponding section. */ + IU32 size; /* Size of corresponding section. */ + struct _SECTION_HEADER *next; /* Next header in linked list. */ +} SECTION_HEADER; + +/* Possible values for 'flags' field of SECTION_HEADER structure. */ +#define HDR_VALID_FLAG 0x1 /* Header points to the beginning of a chunk + or free section. */ +#define HDR_ALLOC_FLAG 0x2 /* Header points to an allocated chunk. */ +#define HDR_COMMITTED_FLAG 0x4 /* Header points to committed chunk, not moveable */ +#define HDR_REMAP_FLAG 0x8 /* chunk is remapped by "AddVirtualMemory" */ + +#define HDR_VALID_ALLOC (HDR_VALID_FLAG|HDR_ALLOC_FLAG) + /* Header points to a section that is valid + and allocated. */ + +#define SECTION_IS_FREE(ptr) (!((ptr)->flags & HDR_ALLOC_FLAG)) + /* Is a section's allocated flag set? */ + +#define SECTION_IS_UNCOMMITTED(ptr) (!((ptr)->flags & HDR_COMMITTED_FLAG)) + /* Is a section's committed flag set? */ + +/* Enumerated type to pass to header management functions. */ +typedef enum +{ + SECT_ALLOC, + SECT_FREE +} SECT_TYPE; + +#define ONE_K (1<<10) /* Speaks for itself. */ +#define ONE_MEG (1<<20) /* Ditto. */ +#define PAGE_SIZE (4 * ONE_K) /* Intel memory page granularity. */ +#define PAGE_MASK (PAGE_SIZE - 1) /* Mask used in rounding to boundary. */ +#define PAGE_SHIFT 12 /* Amount to shift by to get page. */ + +// The following two defines have been replace with MaxIntelMemorySize and +//MaxIntelMemorySize/PAGE_SIZE +//#define MAX_XMS_SIZE (128 * ONE_MEG) /* Maximum memory size. */ +//#define MAX_HEADER_SIZE (MAX_XMS_SIZE / PAGE_SIZE) + +#define A20_WRAP_SIZE (0xfff0) /* Size of A20 wrap area beyond 1M. */ + +/* Convert header table entries to addresses. */ +#define HEADER_TO_ADDRESS(header) \ + (intelMem + (((header) - headerTable) << PAGE_SHIFT)) + +/* Convert addresses to header table entries. */ +#define ADDRESS_TO_HEADER(address) \ + (headerTable + (((address) - intelMem) >> PAGE_SHIFT)) + +/* Local variables. */ +LOCAL IBOOL memInit = FALSE; + /* Is memory system initialised? */ +LOCAL IU8 *intelMem; /* Pointer to intel memory block. */ +LOCAL SECTION_HEADER *headerTable; /* Table of memory section headers. */ +LOCAL IU32 totalFree; /* Total amount of free memory. */ +LOCAL IU32 commitShift; /* Shift to get commitment granularity */ +LOCAL int ZapValue; /* Value to set allocated memory to */ +LOCAL IU32 WOWforceIncrAlloc = 0; /* Force increasing linear address */ +LOCAL SECTION_HEADER *lastAllocPtr = NULL; /* Last chunk allocated. */ + +/* Prototypes for local functions. */ +LOCAL SECTION_HEADER *addHeaderEntry IPT5( + SECTION_HEADER *, prevHeader, + SECTION_HEADER *, nextHeader, + SECT_TYPE, allocFree, + IU8 *, intelAddr, + IU32, size); +LOCAL IBOOL deleteHeaderEntry IPT1( + SECTION_HEADER *, header); +LOCAL void exclusiveHeaderPages IPT5( + IHPE, tableAddress, + IHPE, prev, + IHPE, next, + IHP *, allocAddr, + IU32 *, allocSize); +LOCAL void exclusiveChunkPages IPT4( + SECTION_HEADER *, chunkHeader, + IHP *, allocAddr, + IU32 *, allocSize, + BOOL, Commit); +LOCAL void exclusiveAllocPages IPT6( + IHPE, address, + IU32, size, + IHPE, prevAllocLastAddr, + IHPE, nextAllocFirstAddr, + IHP *, allocAddr, + IU32 *, allocSize); + +/* Global Functions. */ + +/*( +============================== InitIntelMemory ================================= +PURPOSE: + This function reserves the entire Intel address space, committing the + first 1 meg and leaving the rest to be committed as and when required + when new chunks are allocated. +INPUT: + None. +OUTPUT: + Return value - pointer to beginning of intel memory. +================================================================================ +)*/ +GLOBAL IU8 *InitIntelMemory IFN1(IU32, MaxIntelMemorySize) +{ + SYSTEM_INFO SystemInfo; /* Passed to GetSystemInfo API. */ + DWORD tabSize; /* Max. size of header table in bytes. */ + IS32 commitGran; /* Commitment granularity. */ + IU32 temp, /* Used in computing commitShift. */ + initialCommitSize; /* Size of real mode area to commit. */ + SECTION_HEADER *entryPtr; /* Header entry for real mode area. */ + +#ifdef DEBUG_MEM + printf("NTVDM:InitIntelMemory(%lx [%dK])\n", + MaxIntelMemorySize, MaxIntelMemorySize/ONE_K); +#endif + + /* + * Setup the value to initalise allocated memory with + */ + { + char *env; + + if((env = getenv("CPU_INITIALISE_MEMORY")) != 0) + ZapValue = strtol(env, 0, 16); + else + ZapValue = 0xf4; /* HLT instruction */ + + } + + /* + * Find out machine's commitment granularity, and store it as a number of + * bits to shift an address right to give the allocation page it is in. + * This assumes the allocation granularity is a power of two so complain + * if it isn't. + */ + GetSystemInfo(&SystemInfo); + commitGran = (IS32) SystemInfo.dwPageSize; + if ((-commitGran & commitGran) != commitGran) + { + always_trace1("Commitment granularity %#x not a power of two", + commitGran); + return((IU8 *) NULL); + } +#ifdef DEBUG_MEM + printf("NTVDM:Commitment granularity is %lx\n", commitGran); +#endif + commitShift = 0; + for (temp = commitGran; temp > 1; temp >>= 1) + commitShift++; + + /* Reserve the entire memory space. */ + intelMem = (IU8 *) VirtualAlloc((LPVOID) NULL, + (DWORD) MaxIntelMemorySize, + (DWORD) MEM_RESERVE, + (DWORD) PAGE_READWRITE); + if (!intelMem) + { + always_trace1("Failed to reserve %dM of memory", MaxIntelMemorySize >> 20); + return((IU8 *) NULL); + } + + /* + * Allocate the bottom 1 megabyte plus the 20-bit wrap area. Round this + * to an Intel page boundary as this is the granularity of this system. + */ + initialCommitSize = (ONE_MEG + A20_WRAP_SIZE + PAGE_MASK) & + (IU32) ~PAGE_MASK; + if (VirtualAlloc((LPVOID) intelMem, + (DWORD) initialCommitSize, + (DWORD) MEM_COMMIT, + (DWORD) PAGE_READWRITE) == NULL) + { + always_trace0("Could not commit real mode area"); + VirtualFree (intelMem, 0, MEM_RELEASE); /* Free Intel memory */ + return((IU8 *) NULL); + } + + /* Reserve enough space for the entire header table. */ + tabSize = (MaxIntelMemorySize/PAGE_SIZE) * sizeof(SECTION_HEADER); + headerTable = (SECTION_HEADER *) VirtualAlloc((LPVOID) NULL, + tabSize, + (DWORD) MEM_RESERVE, + (DWORD) PAGE_READWRITE); + + if (!headerTable) + { + always_trace0("Failed to reserve header table"); + VirtualFree (intelMem, 0, MEM_RELEASE); /* Free Intel memory */ + return((IU8 *) NULL); + } + + /* + * Initialise linked list with pointers to initial 1M and remaining free + * space and store initial size of free space. + */ + entryPtr = addHeaderEntry((SECTION_HEADER *) NULL, (SECTION_HEADER *) NULL, + SECT_ALLOC, intelMem, initialCommitSize); + + entryPtr->flags |= HDR_COMMITTED_FLAG; + totalFree = MaxIntelMemorySize - initialCommitSize; + + (void) addHeaderEntry(entryPtr, (SECTION_HEADER *) NULL, SECT_FREE, + intelMem + initialCommitSize, totalFree); + + /* Return the address of the start of memory. */ + memInit = TRUE; + return(intelMem); +} + +/*( +============================== FreeIntelMemory ================================= +PURPOSE: + This function frees the entire Intel address space +INPUT: + None. +OUTPUT: + None. +================================================================================ +)*/ + +GLOBAL VOID FreeIntelMemory IFN0() +{ +#ifdef DEBUG_MEM + printf("NTVDM:FreeIntelMemory\n"); +#endif + + /* Free Intel memory */ + VirtualFree (intelMem, 0, MEM_RELEASE); + + /* Free allocation control structure */ + VirtualFree (headerTable, 0, MEM_RELEASE); +} + +/*( +============================ SetWOWforceIncrAlloc =============================== +PURPOSE: + When TRUE is passed, this function sets the WOWforceIncrAlloc variable to + the current thread ID. This will force VdmAllocateVirtualMemory to allocate + blocks of memory with ever increasing linear address's for this thread only. + When FALSE is passed, WOWforceIncrAlloc is cleared and the default + allocation scheme is used. This function is called by WOW based on an app + compatibility flag at start task time and end task time. Power Builder 4 + depends on this. This is not a general solution for multiple threads. Since + the problem we're trying to work around occurs at load time, the allocation + strategy is applied to the most recent thread only. This might not work if + multiple instances of the app are started at the same time. + +INPUT: + None. +OUTPUT: + None. +================================================================================ +)*/ + +GLOBAL VOID SetWOWforceIncrAlloc IFN1(IBOOL, iEnable) +{ + if (iEnable) { + WOWforceIncrAlloc = GetCurrentThreadId(); + } + else { + WOWforceIncrAlloc = 0; + } +#ifdef DEBUG_MEM + printf("NTVDM:SetWOWforceIncrAlloc, WOWforceIncrAlloc: %X\n", WOWforceIncrAlloc); +#endif +} + + +/*( +========================= VdmAllocateVirtualMemory ============================= +PURPOSE: + This interface will allocate the specified number of bytes of virtual + memory, returning the Intel linear address in the variable pointed to + by the Address parameter. The Intel linear address will be page + aligned (this is important). In the event that the memory is + allocated, STATUS_SUCCESS will be returned. In the event of failure, + an appropriate NTSTATUS code will be returned. (In the event that + there is a failure in the cpu for which there is not an appropriate + code, STATUS_UNSUCCESSFUL can be returned. I just want to have an + opportunity to get more information.) +INPUT: + Size - size of memory chunk required in bytes (must be a + multiple of 4K). + + Commit - Commit virtual memory ? +OUTPUT: + Address - INTEL linear address of allocated chunk. + Return value - STATUS_SUCCESS, if the memory is allocated, or an + appropriate NTSTATUS code if not (if there is no + appropriate code STATUS_UNSUCCESSFUL is returned). +================================================================================ +)*/ +GLOBAL NTSTATUS VdmAllocateVirtualMemory IFN3(PULONG, INTELAddress, + ULONG, Size, + BOOL, Commit) +{ + SECTION_HEADER *headerPtr, + *newHeader; + IHP retAddr, + commitAddr; + IU32 commitSize; + +#ifdef DEBUG_MEM + printf("NTVDM:VdmAllocateVirtualMemory(%lx [%dK],%s)\n", + Size, Size/ONE_K, Commit ? "COMMIT" : "DONOT_COMMIT"); +#endif + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmAllocateVirtualMemory before initialisation"); + + /* Round Size up to a multiple of 4K. */ + + if (Size & PAGE_MASK) + Size = (Size + PAGE_MASK) & (~PAGE_MASK); + + + /* Search for a chunk of the required size. If WOWforceIncrAlloc is our */ + /* current thread ID and lastAllocPtr is intialized, force returned */ + /* chunks to have ever increasing linear address's. */ + if ((WOWforceIncrAlloc != 0) && lastAllocPtr + && (GetCurrentThreadId() == WOWforceIncrAlloc)) { +#ifdef DEBUG_MEM + printf("\nNTVDM:VdmAllocateVirtualMemory, using increasing linear address strategy.\n"); +#endif + headerPtr = lastAllocPtr; + } else { + headerPtr = &headerTable[0]; + } + while (headerPtr != NULL) + { + if (SECTION_IS_FREE(headerPtr) && (headerPtr->size >= Size)) + break; + headerPtr = headerPtr->next; + } + + /* Return failure if there is no chunk of the required size. */ + if (headerPtr == NULL) + return(STATUS_NO_MEMORY); + + /* Mark the header as an allocated chunk */ + headerPtr->flags |= HDR_ALLOC_FLAG; + lastAllocPtr = headerPtr; + + /* Add committed status to header. */ + if(Commit) + headerPtr->flags |= HDR_COMMITTED_FLAG; + else + headerPtr->flags &= ~HDR_COMMITTED_FLAG; + + /* Create a new header if there is any space left below the new chunk. */ + if (headerPtr->size > Size) + { + newHeader = addHeaderEntry(headerPtr, + headerPtr->next, + SECT_FREE, + headerPtr->address + Size, + headerPtr->size - Size); + headerPtr->size = Size; + } + + /* Commit any pages that are unique to this chunk. */ + exclusiveChunkPages(headerPtr, &commitAddr, &commitSize, TRUE); + if (commitSize && Commit) + { + retAddr = VirtualAlloc((LPVOID) commitAddr, + (DWORD) commitSize, + (DWORD) MEM_COMMIT, + (DWORD) PAGE_READWRITE); + + if (retAddr != commitAddr) + { + always_trace2("Could not commit %dK at addr %#x", + commitSize / ONE_K, commitAddr); + return(STATUS_NOT_COMMITTED); + } + } + + /* + * Success, so update total free space store and return the address of + * the new chunk to the caller. + */ + totalFree -= Size; + *INTELAddress = ((ULONG) (IHPE) headerPtr->address) - (ULONG) intelMem; + +#ifdef DEBUG_MEM + printf(" => alloc %lxh, commit %lxh\n", + ((ULONG) (IHPE)headerPtr->address) - (ULONG)intelMem, + ((ULONG) (IHPE)commitAddr) - (ULONG)intelMem); + +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("after allocate"); +#endif +#endif + + return(STATUS_SUCCESS); +} + +/*( +========================== VdmCommitVirtualMemory ============================= +PURPOSE: + Commit memory within a previously allocated chunk +INPUT: + Address Intel linear address of memory to commit + Size Size of memory to commit +OUTPUT: + Return value - STATUS_SUCCESS, if the memory is allocated, or an + appropriate NTSTATUS code if not. +=============================================================================== +)*/ + +GLOBAL NTSTATUS VdmCommitVirtualMemory IFN2(ULONG, INTELAddress, + ULONG, Size) +{ + IHP retAddr; + +#ifdef DEBUG_MEM + printf("NTVDM:VdmCommitVirtualMemory(%lxh,%lxh)\n",INTELAddress, Size); +#endif + + retAddr = VirtualAlloc((LPVOID) (intelMem + INTELAddress), + (DWORD) Size, + (DWORD) MEM_COMMIT, + (DWORD) PAGE_READWRITE); + + if(retAddr != (intelMem + INTELAddress)) + { + always_trace2("Could not commit %dK at addr %#x", + Size / ONE_K, INTELAddress); + + return(STATUS_NOT_COMMITTED); + } + + return(STATUS_SUCCESS); +} + +/*( +======================== VdmDeCommitVirtualMemory ============================= +PURPOSE: + Decommit memory within a previously allocated chunk +INPUT: + Address Intel linear address of memory to decommit + Size Size of memory to commit +OUTPUT: + Return value - STATUS_SUCCESS, if the memory is allocated, or an + appropriate NTSTATUS code if not. +=============================================================================== +)*/ + +GLOBAL NTSTATUS VdmDeCommitVirtualMemory IFN2(ULONG, INTELAddress, + ULONG, Size) +{ +#ifdef DEBUG_MEM + printf("NTVDM:VdmDeCommitVirtualMemory(%lxh,%lxh)\n",INTELAddress, Size); +#endif + + + sas_overwrite_memory(INTELAddress, Size); + if (!VirtualFree((LPVOID) (intelMem + INTELAddress), + (DWORD) Size, + (DWORD) MEM_DECOMMIT)) + { + always_trace2("Could not decommit %dK at addr %#x", + Size / ONE_K, INTELAddress); + + return(STATUS_UNSUCCESSFUL); + } + + return(STATUS_SUCCESS); +} + +/*( +============================ VdmFreeVirtualMemory ============================== +PURPOSE: + This interface will free the allocation at the specified Intel linear + address. The above notes on return value apply. +INPUT: + INTELAddress - INTEL address to be freed. +OUTPUT: + Return value - STATUS_SUCCESS, if the memory is allocated, or an + appropriate NTSTATUS code if not (if there is no + appropriate code STATUS_UNSUCCESSFUL is returned). +================================================================================ +)*/ +GLOBAL NTSTATUS VdmFreeVirtualMemory IFN1(ULONG, INTELAddress) +{ + SECTION_HEADER *headerPtr; + IU32 size, + decommitSize; + IHP decommitAddr; + ULONG Address; + + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmFreeVirtualMemory before initialisation"); + +#ifdef DEBUG_MEM + printf("NTVDM:VdmFreeVirtualMemory(%lxh)\n",INTELAddress); +#endif + + /* Calculate chunk address */ + Address = INTELAddress + (ULONG)intelMem; + + /* Get header table entry for address. */ + headerPtr = ADDRESS_TO_HEADER((IU8 *) Address); + + /* + * Check address is correctly aligned and at the top of an allocated + * chunk. + */ + if ((Address & PAGE_MASK) || + (headerPtr->flags & HDR_VALID_ALLOC != HDR_VALID_ALLOC)) + { + always_trace0("Tried to free invalid address"); + return(STATUS_MEMORY_NOT_ALLOCATED); + } + + /* Don't allow freeing of bottom 1 Meg. */ + if (headerPtr == &headerTable[0]) + { + always_trace0("Tried to free real mode area"); + return(STATUS_UNSUCCESSFUL); + } + + /* DON'T free if still mapped to another area of host memory by + * VdmAddVirtualMemory() - ie the PhysRecStructs are in a munged + * state. Free can get called before Remove, and Remove will + * unflag it and call here later. + */ + if (headerPtr->flags & HDR_REMAP_FLAG) + { + always_trace0("Tried to free remapped area"); + return(STATUS_SUCCESS); + } + + + /* Save the size of the chunk before decommitting it. */ + size = headerPtr->size; + + /* Tell the CPU that the contents of the memory are no longer valid. */ + sas_overwrite_memory(INTELAddress, size); + + /* Decommit any memory that is unique to this chunk. */ + exclusiveChunkPages(headerPtr, &decommitAddr, &decommitSize, FALSE); + if (decommitSize) + { + if (!VirtualFree((LPVOID) decommitAddr, + (DWORD) decommitSize, + (DWORD) MEM_DECOMMIT)) + { + always_trace2("Could not decommit %dK at addr %#x", + decommitSize / ONE_K, decommitAddr); + return(STATUS_UNABLE_TO_DECOMMIT_VM); + } + } + + /* + * If chunk is adjacent to a free section absorb this chunk into it. + * Start with next chunk so we don't trash current one before we are + * finished with it. + */ + if (headerPtr->next && SECTION_IS_FREE(headerPtr->next)) + { + headerPtr->size += headerPtr->next->size; + deleteHeaderEntry(headerPtr->next); + } + + /* Absorb into previous section if that is free. */ + if (headerPtr->prev && SECTION_IS_FREE(headerPtr->prev)) + { + headerPtr->prev->size += headerPtr->size; + deleteHeaderEntry(headerPtr); + } + else + { + + /* Otherwise just mark this chunk as free. */ + headerPtr->flags &= (IU32) ~HDR_ALLOC_FLAG; + } + + /* Success, so update total free space store and return. */ + totalFree += size; + + +#ifdef DEBUG_MEM +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("after free"); +#endif +#endif + + return(STATUS_SUCCESS); +} + +/*( +========================== VdmQueryFreeVirtualMemory =========================== +PURPOSE: + This interface returns information about free memory. The total number + of allocatable free bytes is returned in the variable pointed to by + FreeBytes. LargestFreeBlock returns the size of the largest contiguous + block that can be allocated at the present time. This value is + potentially all of the available virtual memory. It may change over + time due to other activities in the system. The above notes on return + value apply. +INPUT: + None. +OUTPUT: + FreeBytes - the total number of allocatable free bytes. + LargestFreeBlock - the size of the largest contiguous block that can + be allocated at the present time. + Return value - STATUS_SUCCESS, if the memory is allocated, or an + appropriate NTSTATUS code if not (if there is no + appropriate code STATUS_UNSUCCESSFUL is returned). +================================================================================ +)*/ +GLOBAL NTSTATUS VdmQueryFreeVirtualMemory IFN2(PULONG, FreeBytes, + PULONG, LargestFreeBlock) +{ + IU32 maxFree = 0; /* Local storage for maximum. */ + SECTION_HEADER *headerPtr; /* Pointer for searching through linked list. */ + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmQueryFreeVirtualMemory before initialisation"); + + /* + * Use a linear search through the linked list to find the largest + * contiguous free space. (This information could be updated as chunks are + * allocated and freed but do it this way for now.) + */ + + for(headerPtr = &headerTable[0] ; + headerPtr != NULL ; + headerPtr = headerPtr->next) + { + if (SECTION_IS_FREE(headerPtr) && (headerPtr->size > maxFree)) + maxFree = headerPtr->size; + } + + *FreeBytes = (ULONG) totalFree; + *LargestFreeBlock = (ULONG) maxFree; + +#ifdef DEBUG_MEM + printf("NTVDM:VdmQueryFreeVirtualMemory() Total %lx [%dK], Largest %lx[%dK]\n", + *FreeBytes, *FreeBytes/ONE_K, *LargestFreeBlock, *LargestFreeBlock/ONE_K); +#endif + + return(STATUS_SUCCESS); +} + +/*( +========================== VdmReallocateVirtualMemory ========================== +PURPOSE: + This interface will reallocate the block of memory at the specified + Intel linear address. The size of the new block is specified by + NewSize. The new address is returned in the variable pointed to by + NewAddress. The new address must be page aligned (this is important). + If the new size is smaller than the old size, the new address must be + the same as the old address (this is also important). The original + data from the reallocated memory must be preserved to + min(old size, new size). The state of any data beyond NewSize is + indeterminate. +INPUT: + INTELOriginalAddress - INTEL address of the chunk to be reallocated. + NewSize - size in bytes the chunk needs to be changed to. +OUTPUT: + INTELNewAddress - new INTEL address of the chunk. +================================================================================ +)*/ +GLOBAL NTSTATUS VdmReallocateVirtualMemory IFN3(ULONG, INTELOriginalAddress, + PULONG, INTELNewAddress, + ULONG, NewSize) +{ + SECTION_HEADER *headerPtr; + IBOOL nextSectIsFree; + IU32 oldSize, + maxSize; + ULONG newAddr; + NTSTATUS status; + ULONG OriginalAddress; + + +#ifdef DEBUG_MEM + printf("NTVDM:VdmReallocateVirtualMemory(%lx [%dK] at %lx)\n", + NewSize, NewSize/ONE_K, INTELOriginalAddress); +#endif + + /* Round NewSize up to a multiple of 4K. */ + if (NewSize & PAGE_MASK) + NewSize = (NewSize + PAGE_MASK) & (~PAGE_MASK); + + /* Calculate chunk address */ + OriginalAddress = INTELOriginalAddress + (ULONG)intelMem; + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmReallocateVirtualMemory before initialisation"); + + /* Get header table entry for address. */ + headerPtr = ADDRESS_TO_HEADER((IU8 *) OriginalAddress); + + + /* Unable to reallocate sparsely commit chunk */ + if(!(headerPtr->flags & HDR_COMMITTED_FLAG)) + { + always_trace0("Tried to reallocate sparsely committed chunk"); + return(STATUS_MEMORY_NOT_ALLOCATED); + } + + + /* + * Check address is correctly aligned and at the top of an allocated + * chunk. + */ + if ((OriginalAddress & PAGE_MASK) || + (headerPtr->flags & HDR_VALID_ALLOC != HDR_VALID_ALLOC)) + { + always_trace0("Tried to reallocate invalid address"); + return(STATUS_MEMORY_NOT_ALLOCATED); + } + + /* If size is the same there is nothing to do. */ + if (NewSize == headerPtr->size) + { + always_trace0("New size equals old size in VdmReallocateVirtualMemory"); + *INTELNewAddress = INTELOriginalAddress; + return(STATUS_SUCCESS); + } + + /* Don't allow reallocation of bottom 1 Meg. */ + if (headerPtr == &headerTable[0]) + { + always_trace0("Tried to reallocate real mode area"); + return(STATUS_UNSUCCESSFUL); + } + + /* ... or if still mapped to another area of host memory by + * VdmAddVirtualMemory() - ouch! + */ + if (headerPtr->flags & HDR_REMAP_FLAG) + { + always_trace0("Tried to reallocate remapped area"); + return(STATUS_UNSUCCESSFUL); + } + + /* Save old size for later. */ + oldSize = headerPtr->size; + + /* Work out whether the chunk needs to be moved. */ + maxSize = headerPtr->size; + if (headerPtr->next && SECTION_IS_FREE(headerPtr->next)) + { + maxSize += headerPtr->next->size; + nextSectIsFree = TRUE; + } + else + { + nextSectIsFree = FALSE; + } + if (NewSize > maxSize) + { + + /* Chunk must move, so allocate a new one. */ + status = VdmAllocateVirtualMemory(&newAddr, NewSize, TRUE); + if (status != STATUS_SUCCESS) + return(status); + + /* Copy old chunk. */ + memcpy((void *) (newAddr + intelMem), (void *) OriginalAddress, + (size_t) oldSize); + + /* Free old chunk. */ + sas_overwrite_memory(INTELOriginalAddress, oldSize); + status = VdmFreeVirtualMemory(INTELOriginalAddress); + if (status != STATUS_SUCCESS) + return(status); + + /* Inform caller of new address. */ + *INTELNewAddress = newAddr; + } + else + { + IHP commitAddr; + IU32 commitSize; + + /* Adjust size of current chunk. */ + headerPtr->size = NewSize; + + /* Remove old pointer to free space if there is one. */ + if (nextSectIsFree) + deleteHeaderEntry(headerPtr->next); + + /* Add new pointer to free space if one is required. */ + if (NewSize < maxSize) + { + (void) addHeaderEntry(headerPtr, + headerPtr->next, + SECT_FREE, + (IU8 *) (OriginalAddress + NewSize), + maxSize - NewSize); + } + + /* If this chunk is committed, commit the memory now covered by it */ + /* in case its size has increased, or decommit the freed up memory */ + if (headerPtr->flags & HDR_COMMITTED_FLAG) + { + if (oldSize < NewSize) { + exclusiveChunkPages(headerPtr, &commitAddr, &commitSize, TRUE); + if (commitSize) + (void) VirtualAlloc((LPVOID) commitAddr, + (DWORD) commitSize, + (DWORD) MEM_COMMIT, + (DWORD) PAGE_READWRITE); + } else { + /* Chunk has shrunk, so free up excess */ + exclusiveChunkPages(headerPtr->next, &commitAddr, &commitSize, FALSE); + if (commitSize) + (void) VirtualFree((LPVOID) commitAddr, + (DWORD) commitSize, + (DWORD) MEM_DECOMMIT); + } + } + + /* Inform caller address has not changed. */ + *INTELNewAddress = OriginalAddress - (ULONG)intelMem; + + /* Update total free space store. */ + totalFree += NewSize - oldSize; + } + +#ifdef DEBUG_MEM + printf("to %lx\n", *INTELNewAddress); +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("after realloc"); +#endif +#endif + /* Success. */ + return(STATUS_SUCCESS); +} + +/*( +============================ VdmAddVirtualMemory =============================== +PURPOSE: + In investigating the things we need to support with the 386, I've come + across an interesting one called dib.drv. Support for this involves calling + CreateDibSection, which returns a pointer to a DIB. The applications then + edit the bits in the dib directly, as well as operating on it using GDI + calls. At least that's my understanding. In view of this, and the potential + for people to create other api with similar properties, it appears that we + need to be able to notify the cpu that a particular region of memory needs + to be added to the intel address space. + + This interface adds virtual memory allocated by the system to the intel + address space. The host linear address of the block to be added is + specified by HostAddress. The pages at this address have already been + allocated and initialized. The CPU should not modify the contents of these + pages, except as part of executing emulated code. The Intel linear address + may be specified by IntelAddress. If IntelAddress is non-NULL, it specifies + the Intel address that the memory should be added at. If IntelAddress is + NULL, the CPU may select the Intel address the memory is at. In all events, + upon return from VdmAddVirtualMemory, IntelAddress will contain the Intel + address of the block of memory. If the function cannot be performed, and + appropriate NTSTATUS code should be returned. + + / The ability to specify Intel Address may be unecessary. I included it for + completeness / +INPUT: + HostAddress - the host linear address of the block to be added. + Size - the size of the block in bytes. +OUTPUT: + IntelAddress - the intel address the block is mapped to. +================================================================================ +)*/ +GLOBAL NTSTATUS VdmAddVirtualMemory IFN3(ULONG, HostAddress, + ULONG, Size, + PULONG, IntelAddress) +{ + IU32 alignfix; + +#ifdef DEBUG_MEM + printf("NTVDM:VdmAddVirtualMemory (%lx [%dK]) at %lx)\n", + Size, Size/ONE_K, HostAddress); +#endif + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmAddVirtualMemory before initialisation"); + + /* Calculate shift required to DWORD align HostAddress */ + if ((alignfix = HostAddress & 0x3) != 0) { + Size += alignfix; + HostAddress -= alignfix; + } + + /* Round Size up to a multiple of 4K. */ + + if (Size & PAGE_MASK) + Size = (Size + PAGE_MASK) & (~PAGE_MASK); + + /* step 1 - reserve the intel address space */ + + if (VdmAllocateVirtualMemory(IntelAddress,Size,FALSE) != STATUS_SUCCESS) + return (STATUS_NO_MEMORY); + + /* step 2 - flush the caches */ + + sas_overwrite_memory(*IntelAddress, Size); + + /* step 3 - replace the PhysicalPageREC.translation entries */ + + VdmSetPhysRecStructs(HostAddress, *IntelAddress, Size); + ADDRESS_TO_HEADER(*IntelAddress+intelMem)->flags |= HDR_REMAP_FLAG; + + /* adjust IntelAddress if HostAddress not DWORD aligned */ + + *IntelAddress += alignfix; + +#ifdef DEBUG_MEM +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("after Add"); +#endif + printf("NTVDM:VdmAddVirtualMemory => *IntelAddress=%lx\n", *IntelAddress); +#endif + + return(STATUS_SUCCESS); +} + +/*( +========================== VdmRemoveVirtualMemory ============================== +PURPOSE: + This interface undoes an address mapping that was performed using + VdmAddVirtualMemory. +INPUT: + IntelAddress - address of block to be removed. +================================================================================ +)*/ +GLOBAL NTSTATUS VdmRemoveVirtualMemory IFN1(ULONG, IntelAddress) +{ + SECTION_HEADER * headerPtr; + ULONG HostAddress,Size; + NTSTATUS status; + +#ifdef DEBUG_MEM + printf("NTVDM:VdmRemoveVirtualMemory at %lx)\n", IntelAddress); +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("before remove"); +#endif +#endif + + /* Make sure memory system is initialised. */ + assert0(memInit, "Called VdmRemoveVirtualMemory before initialisation"); + + /* Make sure IntelAddress is page aligned */ + IntelAddress &= ~PAGE_MASK; + + HostAddress = IntelAddress + (ULONG)intelMem; + + /* Get header table entry for address. */ + headerPtr = ADDRESS_TO_HEADER((IU8 *) HostAddress); + + Size = headerPtr->size; + + /* step 1 - flush the caches */ + + sas_overwrite_memory(IntelAddress, Size); + + /* step 2 - reset the PhysicalPageREC.translation entries */ + +#ifdef DEBUG_MEM + if (Size==0) { + printf("NTVDM:VdmRemoveVirtualMemory WARNING, Size==0\n"); + } +#endif + VdmSetPhysRecStructs(HostAddress, IntelAddress, Size); + ADDRESS_TO_HEADER(IntelAddress+intelMem)->flags &= ~HDR_REMAP_FLAG; + + /* step 3 - free the reserved intel address space */ + +#ifdef DEBUG_MEM +#ifdef DEBUG_MEM_DUMP + DumpAllocationHeaders("after remove (now calling free)"); +#endif +#endif + return VdmFreeVirtualMemory(IntelAddress); +} + +/* Local Functions. */ + +/* +=============================== addHeaderEntry ================================= +PURPOSE: + Add an entry in the header table, corresponding to 'intelAddr'. The + entry will sit between 'prevHeader' and 'nextHeader' in the linked + list. If 'prevHeader' is NULL, the new entry will be the first in the + list. If 'nextHeader' is NULL, the new entry will be the last in the + list. The 'allocFree' parameter states whether the section is to be + marked as allocated or free. The 'size' parameter gives the new + section's size. Returns a pointer to the new header on success, NULL + on failure. +INPUT: + prevHeader - previous header in linked list - may be NULL if the new + header is to be the first in the list. + nextHeader - next header in linked list - may be NULL if the new + header is to be the last in the list. + allocFree - is the new header to be marked as allocated or free? + intelAddr - address of the new entry. + size - size of the new section in bytes. +OUTPUT: + return val - pointer to new section or NULL if there is a problem. +================================================================================ + */ +LOCAL SECTION_HEADER *addHeaderEntry IFN5(SECTION_HEADER *, prevHeader, + SECTION_HEADER *, nextHeader, + SECT_TYPE, allocFree, + IU8 *, intelAddr, + IU32, size) +{ + SECTION_HEADER *newHeader = ADDRESS_TO_HEADER(intelAddr); + /* New header table entry. */ + IHP retAddr, + commitAddr; + IU32 commitSize; + +#ifndef PROD + if (prevHeader) + assert0(newHeader > prevHeader, "prevHeader invalid"); + if (nextHeader) + assert0(newHeader < nextHeader, "nextHeader invalid"); +#endif /* !PROD */ + + /* Commit and zero table header entries if necessary. */ + exclusiveHeaderPages((IHPE) newHeader, (IHPE) prevHeader, + (IHPE) nextHeader, &commitAddr, &commitSize); + if (commitSize) + { + retAddr = VirtualAlloc((LPVOID) commitAddr, + (DWORD) commitSize, + (DWORD) MEM_COMMIT, + (DWORD) PAGE_READWRITE); + + if(retAddr != commitAddr) + { + printf("V.Allocate failed (%xh) [%lxh :%xh]\n",GetLastError(),commitAddr,commitSize); + } + + + if (retAddr == commitAddr) + memset((void *) commitAddr, ZapValue, (size_t) commitSize); + else + return((SECTION_HEADER *) NULL); + } + + /* Fill in header's fields. */ + newHeader->flags = HDR_VALID_FLAG; + if (allocFree == SECT_ALLOC) + newHeader->flags |= HDR_ALLOC_FLAG; + newHeader->address = intelAddr; + newHeader->size = size; + + /* Add it to linked list. */ + if (prevHeader) + prevHeader->next = newHeader; + if (nextHeader) + nextHeader->prev = newHeader; + newHeader->prev = prevHeader; + newHeader->next = nextHeader; + + /* Success. */ + return(newHeader); +} + +/* +=========================== deleteHeaderEntry ================================== +PURPOSE: + Delete an entry in the header table and remove it from the linked list. + If this entry is in an allocation page on its own, decommit the whole + page, otherwise zero the entry. Return TRUE on success, FALSE on + failure. +INPUT: + header - pointer to entry to be removed. +OUTPUT: + return val - TRUE on success, FALSE on failure. +================================================================================ + */ +LOCAL IBOOL deleteHeaderEntry IFN1(SECTION_HEADER *, header) +{ + IHP decommitAddr; + IU32 decommitSize; + + /* If trying to delete the last allocated chunk, invalidate lastAllocPtr. */ + if (header == lastAllocPtr) { + lastAllocPtr = NULL; + } + + /* Find out which pages can be decommitted after this header is freed. */ + exclusiveHeaderPages((IHPE) header, (IHPE) header->prev, + (IHPE) header->next, &decommitAddr, &decommitSize); + + /* Remove header from linked list. */ + if (header->prev) + header->prev->next = header->next; + if (header->next) + header->next->prev = header->prev; + + if (decommitSize) + { + + /* Decommit any allocation pages exclusively covered by 'header'. */ + if (!VirtualFree((LPVOID) decommitAddr, + (DWORD) decommitSize, + (DWORD) MEM_DECOMMIT)) + { + always_trace2("Could not decommit %dK at addr %#x", + decommitSize / ONE_K, decommitAddr); + return(FALSE); + } + } + else + { + + /* Zero header's fields. */ + header->prev = (SECTION_HEADER *) NULL; + header->flags = 0; + header->address = 0; + header->size = 0; + header->next = (SECTION_HEADER *) NULL; + } +} + +/* +========================== exclusiveHeaderPages ================================ +PURPOSE: + Find the allocation pages EXCLUSIVELY covered by the table entry + pointed to by 'header'. The previous and next headers in the table + are pointed to by 'prev' and 'next', which may be NULL if there is + no corresponding table entry. The address of the first page exclusive + to the entry is returned in 'allocAddr', the size in bytes of exclusive + pages is returned in 'allocSize'. If 'allocSize' is zero 'allocAddr' + is undefined. +INPUT: + tableAddress - address of table entry about to be used or removed. + prevAddress - address of previous entry in list. + nextAddress - address of next entry in list. +OUTPUT: + allocAddr - pointer to first byte that needs to be + committed/decommitted (undefined if allocSize is 0). + allocSize - size in bytes that needs to be committed/decommitted. +================================================================================ + */ +LOCAL void exclusiveHeaderPages IFN5(IHPE, tableAddress, + IHPE, prevAddress, + IHPE, nextAddress, + IHP *, allocAddr, + IU32 *, allocSize) +{ + IHPE prevHeaderLastAddr, + nextHeaderFirstAddr; + + /* + * Find out which allocation pages are exclusively covered by the table + * entry pointed to by 'header'. + */ + if (prevAddress) + prevHeaderLastAddr = prevAddress + sizeof(SECTION_HEADER) - 1; + else + prevHeaderLastAddr = (IHPE) 0; + nextHeaderFirstAddr = nextAddress; + exclusiveAllocPages(tableAddress, + (IU32) sizeof(SECTION_HEADER), + prevHeaderLastAddr, + nextHeaderFirstAddr, + allocAddr, + allocSize); +} + +/* +=========================== exclusiveChunkPages ================================ +PURPOSE: + Return any allocation pages EXCLUSIVELY covered by the section of + memory pointed to by 'chunkHeader'. The 'allocAddr' parameter points + at the variable in which to store the address the first allocation + page so covered. The 'allocSize' parameter points at the variable in + which to store the size in bytes of these these pages. This routine + calls 'exclusiveAllocPages' which returns zero in 'allocSize' if there + are no exclusive pages, 'allocAddr' being undefined. The same is + therefore true of this routine. + If we are committing, we must commit any (potentially) uncommitted + pages. If uncommitting, we must not uncommit any pages that are alloced, + as they may be committed also. +INPUT: + chunkHeader - The header table entry pointing at the section of memory + that may need committing/decommitting. +OUTPUT: + allocAddr - pointer to first byte that needs to be + committed/decommitted (undefined if allocSize is 0). + allocSize - size in bytes that needs to be committed/decommitted. + Commit - are we going to commit (true) or decommit this header. +================================================================================ + */ +LOCAL void exclusiveChunkPages IFN4(SECTION_HEADER *, chunkHeader, + IHP *, allocAddr, + IU32 *, allocSize, + BOOL, Commit) +{ + IHPE prevChunkLastAddr, /* Last page previous chunk touches. */ + nextChunkFirstAddr; /* First page next chunk touches. */ + SECTION_HEADER *prevHeader, /* Pointer to previous allocated chunk. */ + *nextHeader; /* Pointer to next allocated chunk. */ + + /* Find previous allocated chunk. */ + prevHeader = chunkHeader->prev; + while ((prevHeader != NULL) && + (Commit?SECTION_IS_UNCOMMITTED(prevHeader):SECTION_IS_FREE(prevHeader))) + prevHeader = prevHeader->prev; + + /* Work out end address of previous chunk. */ + if (prevHeader) + prevChunkLastAddr = (IHPE) prevHeader->address + prevHeader->size - 1; + else + prevChunkLastAddr = (IHPE) 0; + + /* Find next allocated chunk. */ + nextHeader = chunkHeader->next; + while ((nextHeader != NULL) && + (Commit?SECTION_IS_UNCOMMITTED(nextHeader):SECTION_IS_FREE(nextHeader))) + nextHeader = nextHeader->next; + + /* Work out start address of next chunk. */ + if (nextHeader) + nextChunkFirstAddr = (IHPE) nextHeader->address; + else + nextChunkFirstAddr = (IHPE) 0; + + /* + * Find the address range of pages that need to be committed and pass them + * straight up to the caller. + */ + exclusiveAllocPages((IHPE) chunkHeader->address, + chunkHeader->size, + prevChunkLastAddr, + nextChunkFirstAddr, + allocAddr, + allocSize); +#ifdef DEBUG_MEM + printf("NTVDM:Exclusive range to %s %lx+%lx is %lx+%lx\n", + Commit ? "COMMIT" : "DECOMMIT", chunkHeader->address,chunkHeader->size, + *allocAddr, *allocSize); +#endif +} + +/* +============================= exclusiveAllocPages ============================== +PURPOSE: + For a given memory range, find out which allocation pages need to be + committed in order for memory accesses to be allowed across the entire + range. To do this we need to know the address and size of the memory + range. These are passed in 'address' and 'size'. We also need to know + the addresses of the previous and next allocated memory ranges to find + out which allocation pages are already committed. This information is + passed to the function in 'prevAllocLastAddr' and 'nextAllocFirstAddr'. + If there is no previous or next chunk, 'prevAllocLastAddr' or + 'nextAllocFirstAddr' is zero. The address and size that need to be + committed are returned in 'commitAddr' and 'commitSize'. Note that if + 'commitSize' is zero, no memory needs to be committed and 'commitAddr' + is undefined. +INPUT: + address - address of object being checked. + size - size of object being checked. + prevAllocLastAddr - address of last byte of previous allocated + object (or zero if there is none). + nextAllocFirstAddr - address of first byte of next allocated object + (or zero if there is none). +OUTPUT: + allocAddr - pointer to first byte that needs to be + committed/decommitted (undefined if allocSize + is 0). + allocSize - size in bytes that needs to be + committed/decommitted. +================================================================================ + */ +LOCAL void exclusiveAllocPages IFN6(IHPE, address, + IU32, size, + IHPE, prevAllocLastAddr, + IHPE, nextAllocFirstAddr, + IHP *, allocAddr, + IU32 *, allocSize) +{ + IU32 prevAllocLastPage, /* Last page previous chunk touches. */ + currentAllocFirstPage, /* First page current chunk touches. */ + currentAllocLastPage, /* Last page current chunk touches. */ + nextAllocFirstPage, /* First page next chunk touches. */ + firstPage, /* First page that needs committing. */ + lastPage; /* Last page that needs committing. */ + +#ifndef PROD + + /* Check for sensible parameters. */ + if (prevAllocLastAddr) + assert0(address > prevAllocLastAddr, "address out of range"); + if (nextAllocFirstAddr) + assert0(address < nextAllocFirstAddr, "address out of range"); +#endif /* !PROD */ + + /* + * Work out first and last pages of new memory block that need to be + * committed. + */ + currentAllocFirstPage = address >> commitShift; + currentAllocLastPage = (address + size - 1) >> commitShift; + firstPage = currentAllocFirstPage; + +/* Fix horrid nano lookahead bug, but leaves memory leak ? + * Also insufficient anyway in general case + */ +#ifdef PIG + lastPage = currentAllocLastPage+1; +#else + lastPage = currentAllocLastPage; +#endif + + /* + * Now check to see if first or last pages of this allocation are already + * committed by adjacent allocations. + */ + if (prevAllocLastAddr) + { + + /* See if first page of current allocation is already committed. */ + prevAllocLastPage = prevAllocLastAddr >> commitShift; + if (prevAllocLastPage == currentAllocFirstPage) + firstPage++; + } + if (nextAllocFirstAddr) + { + + /* See if last page of current chunk is already committed. */ + nextAllocFirstPage = nextAllocFirstAddr >> commitShift; + if (nextAllocFirstPage == currentAllocLastPage) + lastPage--; + } + + /* + * If first page is less than or equal to last page we have some pages to + * allocate. Return the addrees and size to caller (zero size if nothing + * do. + */ + if (firstPage <= lastPage) + { + *allocAddr = (void *) (firstPage << commitShift); + *allocSize = (lastPage - firstPage + 1) << commitShift; + } + else + *allocSize = 0; +} + + +#ifdef DEBUG_MEM + + +/* +=========================== Dump Header Linked List =========================== +PURPOSE: + Dump the headers linked list controlling allocated blocks + + +INPUT: None +OUTPUT: Via printf + +================================================================================ +*/ + +GLOBAL VOID DumpAllocationHeaders IFN1(char*, where) +{ + + SECTION_HEADER *headerPtr; /* Pointer for searching through linked list. */ + + /* Dump headers */ + printf("NTVDM: Dump Allocation Headers %s\n", where); + printf("ptr address status size (k) commit\n"); + + for(headerPtr = &headerTable[0] ; + headerPtr != NULL ; + headerPtr = headerPtr->next) + { + printf("%08lxh: %08lxh [%s] %08lxh (%05dK)%s%s\n", + headerPtr, + headerPtr->address - intelMem, + SECTION_IS_FREE(headerPtr) ? "FREE" : "USED", + headerPtr->size, headerPtr->size / ONE_K, + headerPtr->flags & HDR_COMMITTED_FLAG ? " COMMITTED" : "", + headerPtr->flags & HDR_REMAP_FLAG ? " REMAPPED" : ""); + } + + printf("\n"); +} + + +#endif DEBUG_MEM + + +#endif /* CPU_40_STYLE */ diff --git a/private/mvdm/softpc.new/host/src/nt_mess.c b/private/mvdm/softpc.new/host/src/nt_mess.c new file mode 100644 index 000000000..40fa77b30 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_mess.c @@ -0,0 +1,27 @@ +#include "host_def.h" +/* + * + * Title : Win32 specific error messages + * + * Description : Text of Win32 specific error messages. + * + * Author : M.McCusker + * + * Notes : Add new error message to array. Message should + * not be longer than 100 characters. + * + * These messages should have an entry in hs_error.h + * and are offset by 1000 + * + * Mods: (r2.3) : Modified the text of the comms error messages. + */ + +/* For Internationalization purposes it my be a good idea to move these + message to the resource file. (Dave Bartlett) */ + +char *hs_err_message[] = { +/* 0 1 2 3 4 5 6 7 8 9 * */ +/* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ +/* FUNC_FAILED */ "Function failed", +/* EHS_SYSTEM_ERROR */ "NTVDM has encountered a System Error", +}; diff --git a/private/mvdm/softpc.new/host/src/nt_mouse.c b/private/mvdm/softpc.new/host/src/nt_mouse.c new file mode 100644 index 000000000..2fbb3a9c8 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_mouse.c @@ -0,0 +1,2630 @@ +#include "windows.h" +#include "insignia.h" +#include "host_def.h" +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include "conapi.h" +#include "xt.h" +#include CpuH +#include "egacpu.h" +#include "trace.h" +#include "debug.h" +#include "gvi.h" +#include "error.h" +#include "config.h" +#include "bios.h" +#include "mouse_io.h" +#include "video.h" +#include "nt_graph.h" +#include "host_nls.h" +#include "sas.h" +#include "ica.h" +#include "idetect.h" +#include "host_rrr.h" +#include "nt_mouse.h" +#include "ntcheese.h" +#include "nt_uis.h" +#include "nt_reset.h" +#include "nt_eoi.h" +#include "nt_event.h" +#include <ntddvdeo.h> +#include "nt_fulsc.h" + + +#define TEXT_MODE 1 +#define GRAPHICS_MODE 2 +#define NOTHING 0xff +#define NOT_INSTALLED 0 +#define INSTALLED 1 + +#define get_pix_height() (get_pc_pix_height() * get_host_pix_height()) + + +GLOBAL BOOL pointer_emulation_status = POINTER_EMULATION_OS; +GLOBAL word VirtualX,VirtualY; +GLOBAL BOOL bPointerOff=FALSE; +GLOBAL MOUSE_STATUS os_pointer_data; + +IMPORT word DRAW_FS_POINTER_SEGMENT, DRAW_FS_POINTER_OFFSET; +IMPORT word POINTER_OFF_SEGMENT, POINTER_OFF_OFFSET; +IMPORT word POINTER_ON_SEGMENT, POINTER_ON_OFFSET; +IMPORT word CP_X_S, CP_X_O, CP_Y_S, CP_Y_O; +IMPORT sys_addr conditional_off_sysaddr; + +IMPORT word F9_SEGMENT,F9_OFFSET; +IMPORT word savedtextoffset,savedtextsegment; + +#ifdef X86GFX +IMPORT sys_addr mouseCFsysaddr; // sas address of internal cursor flag +IMPORT word button_off,button_seg; +IMPORT boolean mouse_io_interrupt_busy; + +#define cursor_in_black_hole(cpx, cpy) \ + (cpx >= black_hole.top_left.x && \ + cpx <= black_hole.bottom_right.x && \ + cpy >= black_hole.top_left.y && \ + cpy <= black_hole.bottom_right.y) + +#endif //X86GFX + + +LOCAL BOOL mouse_state; +LOCAL BOOL bFullscTextBkgrndSaved = FALSE; +LOCAL BOOL bPointerInSamePlace = FALSE; +LOCAL word text_ptr_bkgrnd=0; // safe place for screen background +LOCAL sys_addr old_text_addr; +RECT WarpBorderRect; // in screen coordinates +RECT WarpClientRect; // in client coordinates + +LOCAL POINT pMiddle; // centre point of the current Console window +LOCAL POINT pLast = {0,0}; +LOCAL BOOL bAlertMessage=TRUE; +LOCAL BOOL b256mode=FALSE; +LOCAL int old_x=319; // previous pointer state (position) +LOCAL int old_y=99; // in virtual coordinates. +LOCAL short m2pX=8,m2pY=16; // Mickey to pixel ratios +LOCAL BOOL bFunctionZeroReset = TRUE; +LOCAL BOOL bFunctionFour = FALSE; +LOCAL IS16 newF4x,newF4y; + + + +GLOBAL VOID host_os_mouse_pointer(MOUSE_CURSOR_STATUS *,MOUSE_CALL_MASK *, + + MOUSE_VECTOR *); + +FORWARD BOOL WarpSystemPointer(IS16 *,IS16 *); +FORWARD void MovePointerToWindowCentre(void); +FORWARD void host_mouse_install1(void); +FORWARD void host_mouse_install2(void); +FORWARD void mouse_restore_cursor(void); +FORWARD void deinstall_host_mouse(void); +FORWARD BOOL mouse_installed(void); +FORWARD BOOL mouse_in_use(void); +FORWARD void mouse_reset(void); +FORWARD void mouse_set_position(USHORT,USHORT); +FORWARD void mouse_cursor_display(void); +FORWARD void mouse_cursor_undisplay(void); +FORWARD void mouse_cursor_mode_change(void); +FORWARD BOOL HasConsoleClientRectChanged(void); +FORWARD void MouseDisplay(); +FORWARD void CToS(RECT *); +FORWARD void MouseDetachMenuItem(BOOL); +FORWARD void MouseAttachMenuItem(HANDLE); +FORWARD void MouseReattachMenuItem(HANDLE); +FORWARD void ResetMouseOnBlock(void); +FORWARD void ScaleToWindowedVirtualCoordinates(IS16 *,IS16 *,MOUSE_VECTOR *); +FORWARD void host_m2p_ratio(word *,word *,word *,word *); +FORWARD void host_x_range(word *,word *,word *,word *); +FORWARD void host_y_range(word *,word *,word *,word *); +FORWARD void EmulateCoordinates(half_word,IS16,IS16,IS16 *,IS16 *); +FORWARD void AssembleCallMask(MOUSE_CALL_MASK *); +FORWARD void FullscTextPtr(int, int); +FORWARD void WindowedGraphicsScale(half_word,IS16,IS16,IS16 *,IS16 *); +FORWARD void dummy(short *,short *,unsigned short *); +FORWARD void LimitCoordinates(half_word,IS16 *,IS16 *); +#ifdef X86GFX +FORWARD void CleanUpMousePointer(); +FORWARD void FullscreenWarpSystemPointer(POINT *); +FORWARD void ScaleToFullscreenVirtualCoordinates(IS16 *,IS16 *,MOUSE_VECTOR *); +#endif //X86GFX +FORWARD void TextScale(IS16 *,IS16 *,IS16 *, IS16 *); + +void LazyMouseInterrupt(); +VOID MouseEoiHook(int IrqLine, int CallCount); +BOOLEAN bSuspendMouseInterrupts=FALSE; + + +GLOBAL HOSTMOUSEFUNCS the_mouse_funcs = +{ + mouse_restore_cursor, + deinstall_host_mouse, + mouse_installed, + mouse_in_use, + mouse_reset, + mouse_set_position, + dummy, + mouse_cursor_display, + mouse_cursor_undisplay, + mouse_cursor_mode_change +}; + +BOOL bMouseMenuItemAdded=FALSE; +HMENU hM; + +// +// look up table to convert the video mode number to a mode type indicator +// + +LOCAL half_word TextOrGraphicsModeLUT[] = + { + TEXT_MODE, TEXT_MODE, TEXT_MODE, TEXT_MODE, GRAPHICS_MODE, + GRAPHICS_MODE,GRAPHICS_MODE,NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, GRAPHICS_MODE,GRAPHICS_MODE, + GRAPHICS_MODE,GRAPHICS_MODE,GRAPHICS_MODE,GRAPHICS_MODE,GRAPHICS_MODE, + GRAPHICS_MODE,NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, TEXT_MODE, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, TEXT_MODE, + TEXT_MODE, TEXT_MODE, TEXT_MODE, TEXT_MODE, TEXT_MODE, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, + NOTHING, GRAPHICS_MODE,GRAPHICS_MODE,GRAPHICS_MODE + }; + + +LOCAL int VirtualScrCtrLUTx[] = + { + 319, // mode 0 + 319, // mode 1 + 319, // mode 2 + 319, // mode 3 + 319, // mode 4 + 319, // mode 5 + 319, // mode 6 + 319, // mode 7 + 319, // mode 8 + 319, // mode 9 + 319, // mode a + 319, // mode b + 319, // mode c + 319, // mode d + 319, // mode e + 319, // mode f + 319, // mode 10 + 319, // mode 11 + 319, // mode 12 + 159 // mode 13 + }; +LOCAL int VirtualScrCtrLUTy[] = + { + 99, // mode 0 + 99, // mode 1 + 99, // mode 2 + 99, // mode 3 + 99, // mode 4 + 99, // mode 5 + 99, // mode 6 + 99, // mode 7 + 99, // mode 8 + 99, // mode 9 + 99, // mode a + 99, // mode b + 99, // mode c + 99, // mode d + 99, // mode e + 174, // mode f + 174, // mode 10 + 239, // mode 11 + 239, // mode 12 + 99 // mode 13 + }; + +// +// A look up table to convert a console cell location to a virtual pixel +// coordinate. +// + +int ConsoleTextCellToVPCellLUT[] = + { + 0, 8, 16, 24, 32, 40, 48, 56, + 64, 72, 80, 88, 96, 104, 112, 120, + 128, 136, 144, 152, 160, 168, 176, 184, + 192, 200, 208, 216, 224, 232, 240, 248, + 256, 264, 272, 280, 288, 296, 304, 312, + 320, 328, 336, 344, 352, 360, 368, 376, + 384, 392, 400, 408, 416, 424, 432, 440, + 448, 456, 464, 472, 480, 488, 496, 504, + 512, 520, 528, 536, 544, 552, 560, 568, + 576, 584, 592, 600, 608, 616, 624, 632, + 640, 648, 656, 664, 672, 680, 688, 696 + }; + + +// +// This structure holds the information provided by int 33h functions 7 and 8. +// If one of these functions have been called, then the appropriate flag in +// the structure is set and the handler for this will ignore the default bounds +// for the current video mode and will use the values in the structure instead. +// The flags will clear if a mode change has been detected too. +// + +struct + { + word xmin; + word ymin; + word xmax; + word ymax; + BOOL bF7; + BOOL bF8; + } confine = {0,0,639,199,FALSE,FALSE}; +// +// Mouse interrupt regulation mechanisms +// +BOOLEAN bMseEoiPending = FALSE; +ULONG MseIntLazyCount = 0; + +// +// +// The code starts here +// +// + +GLOBAL void host_mouse_install1(void) +{ +mouse_state = INSTALLED; +RegisterEOIHook(9, MouseEoiHook); +mouse_install1(); +} + + +GLOBAL void host_mouse_install2(void) +{ +mouse_install2(); +} + + +GLOBAL void mouse_restore_cursor() +{ +/* If mouse not in use exit */ + +if(!mouse_in_use()) + return; + +} + +GLOBAL void deinstall_host_mouse() +{ +mouse_state = NOT_INSTALLED; +} + + +GLOBAL BOOL mouse_installed() +{ +return (mouse_state); +} + +void dummy(short *pooh1,short *pooh2, unsigned short *pooh3) +{ +} + +GLOBAL BOOL mouse_in_use() +{ +return(mouse_state == INSTALLED && in_text_mode() == FALSE); +} + +GLOBAL void mouse_reset() +{ +#ifdef X86GFX + +half_word vm; +word xx,yy; + +// +// Set the internal cursor flag to "just off" +// the real driver sets the internal cursor flag to -1 +// so do I. +// + +sas_store(mouseCFsysaddr,0xff); // cursor hidden + +// +// Set the fast track position words in the 16 bit driver. +// First igure out the video mode, and from this, the virtual +// screen centre. +// + +sas_load(0x449,&vm); +xx = (word)VirtualScrCtrLUTx[vm]; +yy = (word)VirtualScrCtrLUTy[vm]; + +// +// The values for the confining virtual pixel coordinate rectangle +// as set up by int 33h functions 7 and 8 are now released and the +// default virtual bounds are used. +// + +confine.bF7 = FALSE; // reset the flag indicating a int 33h function 7 +confine.bF8 = FALSE; // reset the flag indicating a int 33h function 8 + +bFunctionZeroReset = TRUE; + +// +// write the centre position data back to the 16 bit driver. +// + +if(sc.ScreenState == FULLSCREEN) + { + // + // Force a host_os_mouse_pointer call to do the + // write back into the 16 bit driver. + // + LazyMouseInterrupt(); + } +#endif /*X86GFX */ + +// +// Set the default Mickey to pixel ratios +// This is set to 8 pixels to 8 Mickeys in the horizontal direction +// and 16 pixels to 8 Mickeys in the vertical. +// + +m2pX = 8; +m2pY = 16; + +} + + +GLOBAL void mouse_set_position IFN2(USHORT, newx, USHORT, newy) +{ +#ifdef X86GFX +word currentCS, currentIP, currentCX, currentDX; +boolean currentIF; +half_word internalCF; + + // + // write the new position to the 16 bit driver for the fast + // int33hf3 calls on X86. + // + + sas_storew(effective_addr(button_seg,((word)(button_off+2))),(word)newx); + sas_storew(effective_addr(button_seg,((word)(button_off+4))),(word)newy); + +#endif //X86GFX + + +// +// Both Fullscreen and MouseHidePointer enabled windowed mode +// mouse emulations are driven by a set of emulated counters. +// X,Y values are held independently to these counters and rely +// on this function to set up absolute values for X and Y. Note: +// reset does this too. +// + +if(sc.ScreenState == WINDOWED && bPointerOff) + { + newF4x = (IS16)newx; + newF4y = (IS16)newy; + bFunctionFour = TRUE; + return; + } +#ifdef X86GFX +else if(sc.ScreenState == FULLSCREEN) + { + // + // The values that are passed in are hot and fresh from the app. + // Since they have not been tainted by the base, they are still + // in virtual coordinates which is cool. + // + + // + // Get the internal cursor flag from the 16 bit driver + // + + sas_load(mouseCFsysaddr,&internalCF); + + // + // Only draw the pointer if the internal cursor flag + // is zero. Note: less than zero == don't draw. + // + + if(!internalCF) + { + /* if conditional off is diabled or the cursor is outside the + * conditional off rectangle, move the cursor + */ + + if (sas_hw_at_no_check(conditional_off_sysaddr) == 0 || + !cursor_in_black_hole(newx, newy)) + { + currentCS=getCS(); + currentIP=getIP(); + currentCX=getCX(); + currentDX=getDX(); + currentIF=getIF(); + setCS(DRAW_FS_POINTER_SEGMENT); // sacrificial data + setIP(DRAW_FS_POINTER_OFFSET); + setCX((word)newx); + setDX((word)newy); + setIF(FALSE); + // + // call back to 16bits move cursor code. + // + + host_simulate(); + + // + // Tidy up + // + + setCX(currentCX); + setDX(currentDX); + setCS(currentCS); + setIP(currentIP); + setIF(currentIF); + } + else { + /* the cursor was moved into the conditional rectangle, hide it */ + sas_store(mouseCFsysaddr, 0xff); + host_hide_pointer(); + } + } + newF4x = (IS16)newx; + newF4y = (IS16)newy; + bFunctionFour = TRUE; + + // + // update the last mouse position global locators + // + + old_x = newx; + old_y = newy; + } +#endif //X86GFX +} + +GLOBAL void mouse_cursor_display() +{ +} + +GLOBAL void mouse_cursor_undisplay() +{ +} + +GLOBAL void mouse_cursor_mode_change() +{ +} + + +GLOBAL void host_mouse_conditional_off_enabled(void) +{ +#ifdef X86GFX + word x, y; + + /* hide the cursor if + * (1). we are in full screen and + * (2). the cursor is on and is in the conditional area + */ + if (sc.ScreenState == FULLSCREEN && + !sas_hw_at_no_check(mouseCFsysaddr)) { + + x = sas_w_at_no_check(effective_addr(CP_X_S, CP_X_O)); + y = sas_w_at_no_check(effective_addr(CP_Y_S, CP_Y_O)); + if (cursor_in_black_hole(x, y)) { + sas_store(mouseCFsysaddr, 0xff); + host_hide_pointer(); + } + } +#endif + + +} +//============================================================================== +// Hook function that forms the communication transition between +// the host and the base for os pointer emulation. This function +// is called by mouse_int1() which lives in mouse_io.c +//============================================================================== + + +VOID host_os_mouse_pointer(MOUSE_CURSOR_STATUS *mcs,MOUSE_CALL_MASK *call_mask, + MOUSE_VECTOR *counter) +{ +#ifdef X86GFX +sys_addr int33f3addr; +#endif // X86GFX + +host_ica_lock(); // synch with the event thread + +GetNextMouseEvent(); + +#ifdef X86GFX + +if(sc.ScreenState == FULLSCREEN) + { + ScaleToFullscreenVirtualCoordinates(&mcs->position.x,&mcs->position.y,counter); + } +else +#endif // X86GFX + { + ScaleToWindowedVirtualCoordinates(&mcs->position.x,&mcs->position.y,counter); + } + +// +// Create a condition mask for use by any call back installed +// by the application. +// + +AssembleCallMask(call_mask); + +// +// Tell the base about the button state +// + +mcs->button_status=os_pointer_data.button_l | os_pointer_data.button_r<<1; + +host_ica_unlock(); // synch with the event thread + + +// +// Has the pointer moved since the last mouse interrupt. +// This can happen if a button press occurs but no physical +// movement of the mouse body takes place. +// + +if(bPointerInSamePlace) + { + // + // The mouse has not moved since the last mouse + // hardware interrupt. + // + + *call_mask &= ~1; + } +else + { +#ifdef X86GFX + half_word internalCF; +#endif // X86GFX + + // + // The mouse has moved. + // + + *call_mask |= 1; + +#ifdef X86GFX + + // + // Inquire from the 16 bit driver whether or not the + // pointer can be drawn. + // internalCF < 0 -> cannot draw + // internalCF == 0 okay to draw. + // + + sas_load(mouseCFsysaddr,&internalCF); + + // + // If the system has fullscreen capabilities and is in fullscreen + // mode, then if the pointer has been switched on, draw it on the + // fullscreen display. + // + + if(sc.ScreenState == FULLSCREEN && !internalCF) + { + half_word v; + static half_word hwLastModeType; + + if (sas_hw_at_no_check(conditional_off_sysaddr) == 0 || + !cursor_in_black_hole(mcs->position.x, mcs->position.y)) + { + // + // Get the current BIOS video mode a la B.D.A. + // + + sas_load(0x449,&v); + + if((hwLastModeType = TextOrGraphicsModeLUT[v]) == GRAPHICS_MODE) + { + word currentCS,currentIP; // save those interesting Intel registers + word currentCX,currentDX; + boolean currentIF; + + // + // Do the host simulate here to draw the cursor image + // for the full screen graphics + // + + currentCS=getCS(); + currentIP=getIP(); + currentCX=getCX(); + currentDX=getDX(); + currentIF=getIF(); + setCS(DRAW_FS_POINTER_SEGMENT); + setIP(DRAW_FS_POINTER_OFFSET); + setCX(mcs->position.x); + setDX(mcs->position.y); + setIF(FALSE); + // + // call to 16bits move cursor code + // + + host_simulate(); + + // + // Restore the 16 bit context. + // + + setCX(currentCX); + setDX(currentDX); + setCS(currentCS); + setIP(currentIP); + setIF(currentIF); + } + else // TEXT_MODE + { + // + // if there has been a switch from graphics mode to text mode + // then there cannot have been a backround saved. + // + + if(hwLastModeType == GRAPHICS_MODE) + { + bFullscTextBkgrndSaved = FALSE; + hwLastModeType = TEXT_MODE; + } + + // + // Use some 32 bit code to draw the text pointer because + // no hardware i/o is involved and we need only to write to + // the display buffer (16 bit code is needed to do video + // i/os in fullscreen mode). + // + + FullscTextPtr(mcs->position.x,mcs->position.y); + } + } + else { + sas_store(mouseCFsysaddr, 0xff); + host_hide_pointer(); + } + } +#endif // X86GFX + } + + +// +// Write data to the 16 bit driver for int 33h function 3 to pick up +// without having to BOP to the 32 bit side. +// Int 33h function 3 requires this data: +// BX = button status +// CX = virtual pixel position in x +// DX = virtual pixel position in y +// + +#ifdef X86GFX +int33f3addr = effective_addr(button_seg,button_off); +sas_storew(int33f3addr,mcs->button_status); +sas_storew(int33f3addr+=2, (word)(mcs->position.x)); +sas_storew(int33f3addr+=2, (word)(mcs->position.y)); +#endif //X86GFX +} + +//============================================================================== +// Function to munge the status register value for the InPort adapter. +// Nothing much else to say about it really. +// +//============================================================================== + +void AssembleCallMask(MOUSE_CALL_MASK *call_mask) +{ +static int old_l_button=0; // previous mouse button state +static int old_r_button=0; + + +// +// add in the left button current status +// + +if(os_pointer_data.button_l) + { + // + // Left button is down. + // + + if(!old_l_button) + { + // + // The button has just been pressed + // + + *call_mask |= (1<<1); + } + else + { + // + // The button was down on the last hardware interrupt, so + // release the edge detect. + // + + *call_mask &= ~(1<<1); + } + } +else + { + // + // Left button is up. + // + + if(old_l_button) + { + // + // The button has just been released + // + + *call_mask |= (1<<2); + } + else + { + // + // The button was up on the last hardware interrupt, so + // release the edge detect. + // + + *call_mask &= ~(1<<2); + } + } + +// +// add in the right button current status +// + +if(os_pointer_data.button_r) + { + // + // Right button is down. + // + + if(!old_r_button) + { + // + // The button has just been pressed + // + + *call_mask |= (1<<3); + } + else + { + // + // The button was down on the last hardware interrupt, so + // release the edge detect. + // + + *call_mask &= ~(1<<3); + } + } +else + { + // + // Right button is up. + // + + if(old_r_button) + { + // + // The button has just been released + // + + *call_mask |= (1<<4); + } + else + { + // + // The button was up on the last hardware interrupt, so + // release the edge detect. + // + + *call_mask &= ~(1<<4); + } + } + +// +// +// save the current mouse button status. +// + +old_l_button = os_pointer_data.button_l; +old_r_button = os_pointer_data.button_r; + +} + +#ifdef X86GFX +//========================================================================= +// Function to scale mouse coordinates as retrieved from USER +// to virtual coordinates as defined by the Microsoft Mouse +// Programmer's Reference. +//========================================================================= + +void ScaleToFullscreenVirtualCoordinates(IS16 *outx,IS16 *outy, + MOUSE_VECTOR *counter) +{ +half_word video_mode,textorgraphics; +IS16 internalX = 0, internalY = 0; +static IS16 lastinternalX=0, lastinternalY=0; +POINT vector; // Magnitude and direction since last call + + +// +// Manage the system pointer so that it never sticks to a system +// imposed boundary. Also get a relative displacement of the mouse. +// + +FullscreenWarpSystemPointer(&vector); + +// +// return the internal counter values back to the base +// code for it to use to generate the counters there. +// + +counter->x = (MOUSE_SCALAR)vector.x; +counter->y = (MOUSE_SCALAR)vector.y; + +// +// Get the current BIOS video mode from the B.D.A. This comes +// in handy in a couple of places later. +// + +sas_load(0x449,&video_mode); + +// +// checkout some global flags with indicate if one of the int 33h +// functions which are capable of changing the position of the +// DOS mouse driver pointer have been called since the last mouse +// hardware interrupt. +// + +if(bFunctionZeroReset) + { + // + // Calculate the centre of the default virtual screen + // and set the current generated coordinates to it. + // + + internalX = (IS16)VirtualScrCtrLUTx[video_mode]; + internalY = (IS16)VirtualScrCtrLUTy[video_mode]; + + bFunctionZeroReset = FALSE; + } +else if(bFunctionFour) + { + // + // The application has set the pointer to a new location. + // Tell the internal cartesian coordinate system about this. + // + + internalX = newF4x; // This is where the pointer was set to + internalY = newF4y; // by the app on the last pending call to f4 + + // + // Don't come in here again until the next function 4. + // + + bFunctionFour = FALSE; + } +else + { + // + // The most frequent case. Determine the new, raw pointer position + // by adding the system pointer movement vector to the last position + // of the emulated pointer. + // + + internalX = lastinternalX + (IS16)vector.x; + internalY = lastinternalY + (IS16)vector.y; + } + +// +// use the video mode to determine if we're running text or graphics +// + +textorgraphics=TextOrGraphicsModeLUT[video_mode]; + +// +// Scale the coordinates appropriately for the current video mode +// and the type (text or graphics) that it is. +// + +if(textorgraphics == TEXT_MODE) + { + // + // The virtual cell block is 8 by 8 virtual pixels for any text mode. + // This means that the cell coordinates in virtual pixels increments + // by 8 in the positive x and y directions and the top left hand corner + // of the cell starts at 0,0 and has the virtual pixel value for the + // whole text cell. + // + + TextScale(&internalX,&internalY,outx,outy); + } + +else // GRAPHICS_MODE + { + LimitCoordinates(video_mode,&internalX,&internalY); + *outx = internalX; + *outy = internalY; + } + +// +// Set up the current emulated position for next time through +// this function. +// + +lastinternalX = internalX; +lastinternalY = internalY; + +// +// Signal that the pointer hasn't moved, if it hasn't +// + +bPointerInSamePlace = (!vector.x && !vector.y) ? TRUE : FALSE; + +// +// save the current position for next time. +// + +old_x = *outx; +old_y = *outy; +} + +//============================================================================== +// Function to make sure that the system pointer can be made to move in a +// given cartesian direction without hitting and finite boundaries as specified +// by the operating system. +//============================================================================== +void FullscreenWarpSystemPointer(POINT *vector) +{ +static POINT pLast; // System pointer position data from last time through +POINT pCurrent; + +// +// Get a system mouse pointer absolute position value back from USER. +// + +GetCursorPos(&pCurrent); + +// +// Calculate the vector displacement of the system pointer since +// the last call to this function. +// + +vector->x = pCurrent.x - pLast.x; +vector->y = pCurrent.y - pLast.y; + +// +// Has the system pointer hit a border? If so, warp the system pointer +// back to the convienient location of 0,0. +// + + +if(pCurrent.x >= (LONG)1000 || pCurrent.x <= (LONG)-1000 || + pCurrent.y >= (LONG)1000 || pCurrent.y <= (LONG)-1000) + { + // + // If the counters have warped, set the system pointer + // to the relavent position. + // + + SetCursorPos(0,0); + pLast.x = 0L; // prevent a crazy warp + pLast.y = 0L; + } +else + { + // + // update the last position data of the + // system pointer for next time through. + // + pLast = pCurrent; + } +} + +#endif // X86GFX + +//========================================================================= +// Function to scale mouse coordinates as returned by the event loop +// mechanism to virtual coordinates as defined by the Microsoft Mouse +// Programmer's Reference. The method used for scaling depends on the style +// of mouse buffer selected, the current video mode and if (for X86) the +// video system is operating in full screen or windowed mode. +// +// Output: Virtual cartesian coordinates in the same pointers +//========================================================================= + +void ScaleToWindowedVirtualCoordinates(IS16 *outx,IS16 *outy, + MOUSE_VECTOR *counter) +{ +half_word video_mode,textorgraphics; +SAVED SHORT last_text_good_x = 0, last_text_good_y = 0; + +sas_load(0x449,&video_mode); + +// +// Follow different code paths if the user has the system pointer +// hidden or displayed. +// + +if(!bPointerOff) + { + // + // The pointer has not been hidden by the user, so use the + // x,y values as got from the system pointer via the Windows + // messaging system. + // + + // + // get the video mode to determine if we're running text or graphics + // + + textorgraphics=TextOrGraphicsModeLUT[video_mode]; + + if(textorgraphics == TEXT_MODE) + { + // + // validate received data to ensure not graphics mode coords + // received during mode switch. + // + + if(os_pointer_data.x > 87) + { + *outx = last_text_good_x; + } + else + { + *outx = ConsoleTextCellToVPCellLUT[os_pointer_data.x]; + last_text_good_x = *outx; + } + if(os_pointer_data.y > 87) + { + *outy = last_text_good_y; + } + else + { + *outy = ConsoleTextCellToVPCellLUT[os_pointer_data.y]; + last_text_good_y = *outy; + } + } + else // GRAPHICS_MODE + { + // + // If the mouse is NOT in a warping mode, then x,y's as received + // from the console are scaled if they are for a low resolution + // video mode and these are what the application sees and the + // system pointer image is in the correct place to simulate the + // 16 bit pointer. + // If the application decides to extend the x,y bounds returned + // from the driver beyond the limits of the console being used, + // these x,y's are not appropriate, and the mouse must be switched + // into warp mode by the user and the code will emulate the x,y + // generation. + // + + WindowedGraphicsScale(video_mode,(IS16)(os_pointer_data.x), + (IS16)(os_pointer_data.y),outx,outy); + } + + // + // No warping, so set up the old_x and old_y values directly. + // Signal that the pointer hasn't moved, if it hasn't + // + + bPointerInSamePlace = (old_x == *outx && old_y == *outy) ? TRUE : FALSE; + + // + // Set these statics for the next time through. + // + + old_x = *outx; + old_y = *outy; + } +else + { + // + // The user has set the system pointer to be hidden via the + // console's system menu. + // Handle by emulating the counters and generating absolute x,y + // data from this. + // + + IS16 move_x,move_y; + + // + // Get positional data from the system pointer and maintain some + // counters. + // + + if(WarpSystemPointer(&move_x,&move_y)) + { + // + // The mouse moved. + // Generate some new emulated absolute position information. + // + + EmulateCoordinates(video_mode,move_x,move_y,outx,outy); + + // + // Save up the current emulated position for next time through. + // + + + old_x = *outx; + old_y = *outy; + + // + // Send back the relative motion since last time through. + // + + counter->x = move_x; + counter->y = move_y; + + bPointerInSamePlace = FALSE; + } + else + { + // + // No recorded movement of the mouse. + // + + *outx = old_x; + *outy = old_y; + counter->x = counter->y = 0; + bPointerInSamePlace = TRUE; + } + } +} + + +//============================================================================== +// Function to scale the incoming fullscreen coordinates to mouse motion (both +// absolute and relative) for fullscreen text mode. +// Note: if the application chooses to, it can reset the virtual coordinate +// bounds of the virtual screen. This function checks the bound flags and either +// selects the default values or the app imposed values. +// +// This function is also used to modify the coordinates produced directly from +// the motion counters in windowed text mode. +//============================================================================== + +void TextScale(IS16 *iX,IS16 *iY,IS16 *oX, IS16 *oY) +{ +half_word no_of_rows; + +// +// Calculate the current system pointer location in virtual +// pixels for the application. +// + +if(confine.bF7) + { + // + // Limits have been imposed by the application. + // + + if(*iX < confine.xmin) + { + *iX = confine.xmin; + } + else if(*iX > confine.xmax) + { + *iX = confine.xmax; + } + } +else // use the default virtual screen constraints. + { + // + // No limits have been imposed by the application. + // x is always 0 -> 639 virtual pixels for text mode + // + + if(*iX < 0) + { + *iX = 0; + } + else if(*iX > 639) + { + *iX = 639; + } + } + +// +// Bind the y cartesian coordinate appropriately +// + +if(confine.bF8) + { + // + // Limits have been imposed by the application. + // + + if(*iY < confine.ymin) + { + *iY = confine.ymin; + } + else if(*iY > confine.ymax) + { + *iY = confine.ymax; + } + } +else + { + // + // The application has not imposed constraints on the Y virtual pixel + // motion, so confine the Y movement to the default virtual pixel size + // of the virtual screen for the current video mode. + // + + if(*iY < 0) + { + *iY = 0; + } + else + { + // + // Get the number of text rows minus one, from the B.D.A. + // + + sas_load(0x484,&no_of_rows); + + switch(no_of_rows) + { + case 24: + { + // + // 25 rows, so there are 200 vertical virtual pixels + // + if(*iY > 199) + { + *iY = 199; + } + break; + } + case 42: + { + // + // 43 rows, so there are 344 vertical virtual pixels + // + if(*iY > 343) + { + *iY = 343; + } + break; + } + case 49: + { + // + // 50 rows, so there are 400 vertical virtual pixels + // + if(*iY > 399) + { + *iY = 399; + } + break; + } + default: + { + // + // default - assume 25 rows, so there are + // 200 vertical virtual pixels + // + if(*iY > 199) + { + *iY = 199; + } + break; + } + } + } + } +*oX = *iX; +*oY = *iY; +} + + +//============================================================================== +// Fit the raw x,y coordinates generated from the counters to the bounds of +// the virtual screen that is currently set up. This can be set up either by +// the application (in the confine structure) or as set by the mouse driver +// as default. +//============================================================================== + +void LimitCoordinates(half_word vm,IS16 *iX,IS16 *iY) +{ +// +// Select the appropriate conditioning code for +// the current video mode. +// +switch(vm) + { + + // + // Do the common text modes. + // + + case(2): + case(3): + case(7): + { + IS16 oX,oY; + + // + // Scale the generated coordinates for the given text mode + // and the number of rows of text displayed on the screen. + // + + TextScale(iX,iY, &oX, &oY); + *iX = oX; + *iY = oY; + break; + } + + // + // The regular VGA supported graphics video modes. + // + // The following modes are all 640 x 200 virtual pixels + // + case(4): + case(5): + case(6): + case(0xd): + case(0xe): + case(0x13): + { + if(confine.bF7) + { + // + // Limits have been imposed by the application. + // + + if(*iX < confine.xmin) + { + *iX = confine.xmin; + } + else if(*iX > confine.xmax) + { + *iX = confine.xmax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + } + + if(confine.bF8) + { + // + // Limits have been imposed by the application. + // + + if(*iY < confine.ymin) + { + *iY = confine.ymin; + } + else if(*iY > confine.ymax) + { + *iY = confine.ymax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + if(*iY < 0) + *iY = 0; + else if(*iY > 199) + *iY = 199; + } + break; + } + // + // The following modes are all 640 x 350 virtual pixels + // + case(0xf): + case(0x10): + { + if(confine.bF7) + { + // + // Limits have been imposed by the application. + // + + if(*iX < confine.xmin) + { + *iX = confine.xmin; + } + else if(*iX > confine.xmax) + { + *iX = confine.xmax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + } + + if(confine.bF8) + { + // + // Limits have been imposed by the application. + // + + if(*iY < confine.ymin) + { + *iY = confine.ymin; + } + else if(*iY > confine.ymax) + { + *iY = confine.ymax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + + if(*iY < 0) + *iY = 0; + else if(*iY > 349) + *iY = 349; + } + break; + } + // + // The following modes are all 640 x 480 virtual pixels + // + case(0x11): + case(0x12): + { + if(confine.bF7) + { + // + // Limits have been imposed by the application. + // + + if(*iX < confine.xmin) + { + *iX = confine.xmin; + } + else if(*iX > confine.xmax) + { + *iX = confine.xmax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + } + + if(confine.bF8) + { + // + // Limits have been imposed by the application. + // + + if(*iY < confine.ymin) + { + *iY = confine.ymin; + } + else if(*iY > confine.ymax) + { + *iY = confine.ymax; + } + } + else + { + // + // The application has not imposed limits, so use + // the default virtual screen bounds as defined byt + // the mouse driver. + // + + if(*iY < 0) + *iY = 0; + else if(*iY > 479) + *iY = 479; + } + break; + } + + // + // From here on down are the Video7 modes + // + + case(0x60): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 751) + *iX = 751; + + if(*iY < 0) + *iY = 0; + else if(*iY > 407) + *iY = 407; + break; + } + case(0x61): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 719) + *iX = 719; + + if(*iY < 0) + *iY = 0; + else if(*iY > 535) + *iY = 535; + break; + } + case(0x62): + case(0x69): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 799) + *iX = 799; + + if(*iY < 0) + *iY = 0; + else if(*iY > 599) + *iY = 599; + break; + } + case(0x63): + case(0x64): + case(0x65): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 1023) + *iX = 1023; + + if(*iY < 0) + *iY = 0; + else if(*iY > 767) + *iY = 767; + break; + } + case(0x66): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + + if(*iY < 0) + *iY = 0; + else if(*iY > 399) + *iY = 399; + break; + } + case(0x67): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + + if(*iY < 0) + *iY = 0; + else if(*iY > 479) + *iY = 479; + break; + } + case(0x68): + { + if(*iX < 0) + *iX = 0; + else if(*iX > 719) + *iX = 719; + + if(*iY < 0) + *iY = 0; + else if(*iY > 539) + *iY = 539; + break; + } + default: + { + if(*iX < 0) + *iX = 0; + else if(*iX > 639) + *iX = 639; + + if(*iY < 0) + *iY = 0; + else if(*iY > 199) + *iY = 199; + break; + } + } +} + +//============================================================================== +// Function to scale the incoming windowed coordinates since the window size +// can be larger (for the low resolution modes) than the virtual screen size +// for that mode. +//============================================================================== + +void WindowedGraphicsScale(half_word vm,IS16 iX,IS16 iY,IS16 *oX, IS16 *oY) +{ +switch(vm) + { + // + // The following modes are all 640 x 200 virtual pixels + // + case(4): + case(5): + case(6): + case(0xd): + case(0xe): + case(0x13): + { + // + // Low resolution graphics modes. The window is 640 x 400 real host + // pixels, but the virtual screen resolution is 640 x 200. Hence + // must divide the y value by 2 to scale appropriately. + // + + iY >> 1; + break; + } + } +// +// prepare the cartesian coordinate values to return. +// + +*oX = iX; +*oY = iY; +} + +//=========================================================================== +// Function to turn on the mouse cursor in FULLSCREEN mode. +// Note: This function only gets called after the 16 bit code checks +// to see if the internal cursor flag is zero. The 16 bit code does +// not do the BOP if, after incrementing this counter, the above is +// true. +//=========================================================================== + +void host_show_pointer() +{ +#ifdef X86GFX + +if(sc.ScreenState == FULLSCREEN) + { + half_word v; + sas_load(0x449,&v); + + if(TextOrGraphicsModeLUT[v] == GRAPHICS_MODE) + { + word currentCS,currentIP; // save those interesting Intel registers + boolean currentIF; + + sas_storew(effective_addr(CP_X_S,CP_X_O),(word)old_x); + sas_storew(effective_addr(CP_Y_S,CP_Y_O),(word)old_y); + currentCS=getCS(); + currentIP=getIP(); + currentIF=getIF(); + setCS(POINTER_ON_SEGMENT); + setIP(POINTER_ON_OFFSET); + setIF(FALSE); + host_simulate(); + + setCS(currentCS); + setIP(currentIP); + setIF(currentIF); + } + else //TEXT_MODE + { + FullscTextPtr(old_x,old_y); + } + + LazyMouseInterrupt(); + } +#endif // X86GFX +} + +//=========================================================================== +// Function to turn off the mouse cursor in FULLSCREEN mode. +// Note: This function only gets called after the 16 bit code checks +// to see if the internal cursor flag is zero. The 16 bit code does +// not do the BOP if, after decrementing this counter, the above is +// true. +//=========================================================================== + +void host_hide_pointer() +{ +#ifdef X86GFX + +if(sc.ScreenState == FULLSCREEN) + { + half_word v; + + sas_load(0x449,&v); + + if(TextOrGraphicsModeLUT[v] == GRAPHICS_MODE) + { + word currentCS,currentIP; // save those interesting Intel registers + boolean currentIF; + + currentCS=getCS(); + currentIP=getIP(); + currentIF=getIF(); + setCS(POINTER_OFF_SEGMENT); + setIP(POINTER_OFF_OFFSET); + setIF(FALSE); + host_simulate(); + + setCS(currentCS); + setIP(currentIP); + setIF(currentIF); + } + else //TEXT_MODE + { + if(bFullscTextBkgrndSaved) + { + sas_storew(old_text_addr,text_ptr_bkgrnd); + bFullscTextBkgrndSaved = FALSE; + } + } + LazyMouseInterrupt(); + } +#endif // X86GFX +} + +//========================================================================= +// Function to remove the mouse pointer item from the console system menu +// when SoftPC lets an application quit or iconise. +// If the system pointer is OFF i.e. clipped to a region in the current window, +// then relinquish it to the system. +// +// bForce allows the code which gets called when there is a fullscreen to +// windowed graphics switch on x86 to force the menu item off. +//========================================================================= + +void MouseDetachMenuItem(BOOL bForce) +{ +if(bMouseMenuItemAdded || bForce) + { + DeleteMenu(hM,IDM_POINTER,MF_BYCOMMAND); + bMouseMenuItemAdded=FALSE; + ClipCursor(NULL); + } +bAlertMessage=TRUE; // blocking, so reset the int33h f11 alert mechanism +} + +void MouseAttachMenuItem(HANDLE hBuff) +{ +if(!bMouseMenuItemAdded) + { + // + // Read in the relavent string from resource + // + + hM = ConsoleMenuControl(hBuff,IDM_POINTER,IDM_POINTER); + AppendMenu(hM,MF_STRING,IDM_POINTER,szHideMouseMenuStr); + bMouseMenuItemAdded=TRUE; + + // + // initial state -> system pointer is ON + // + + bPointerOff=FALSE; + } +} + +//========================================================================= +// Function to determine if the active output buffer has changed if the VDM +// has done something weird like resized or gone from graphics to fullscreen +// or vice versa. If so, a new handle to the new buffer must be got, and the +// old menu item deleted and a new menu item attach so that the new buffer +// "knows" about the menu item I.D. +//========================================================================= + +void MouseReattachMenuItem(HANDLE hBuff) +{ +static HANDLE hOld = 0; // The handle for the last buffer selected. + +// +// If the output buffer has not changed, then don't do anything. +// + +if(hOld == hBuff) + return; + +// +// First thing, remove the old menu item. +// + +MouseDetachMenuItem(TRUE); + +// +// Next, Add in the new menu item for the current buffer. +// + +MouseAttachMenuItem(hBuff); + +// +// Record the value of the latest buffer for next time. +// + +hOld = hBuff; +} + +void MouseHide(void) +{ + +ModifyMenu(hM,IDM_POINTER,MF_BYCOMMAND,IDM_POINTER, + (LPTSTR)szDisplayMouseMenuStr); + +// +// Clip the pointer to a region inside the console window +// and move the pointer to the window centre +// + +while(ShowConsoleCursor(sc.ActiveOutputBufferHandle,FALSE)>=0) + ; +MovePointerToWindowCentre(); +bPointerOff=TRUE; +} + +void MouseDisplay(void) +{ + +ModifyMenu(hM,IDM_POINTER,MF_BYCOMMAND,IDM_POINTER, + (LPTSTR)szHideMouseMenuStr); + +// +// Let the pointer move anywhere on the screen +// + +ClipCursor(NULL); +while(ShowConsoleCursor(sc.ActiveOutputBufferHandle,TRUE)<0) + ; +bPointerOff=FALSE; +} + +void MovePointerToWindowCentre(void) +{ +RECT rTemp; + +// +// Get current console client rectangle, set the clipping region to match +// the client rect. Retrieve the new clipping rect from the system (is +// different from what we requested!) and save it. +// +VDMConsoleOperation(VDM_CLIENT_RECT,&WarpClientRect); +rTemp = WarpClientRect; +CToS(&rTemp); +ClipCursor(&rTemp); +GetClipCursor(&WarpBorderRect); + +// +// Note : LowerRight clip point is exclusive, UpperLeft point is inclusive +// +WarpBorderRect.right--; +WarpBorderRect.bottom--; + +pMiddle.x = ((WarpBorderRect.right - WarpBorderRect.left)>>1) + +WarpBorderRect.left; +pMiddle.y = ((WarpBorderRect.bottom - WarpBorderRect.top)>>1) + +WarpBorderRect.top; +// +// move the pointer to the centre of the client area +// + +SetCursorPos((int)pMiddle.x,(int)pMiddle.y); + +// +// Prevent the next counter calculation from resulting in a +// large warp. +// + +pLast = pMiddle; +} + +//============================================================================= +// Function to convert a rectangle structure from client coordinates to +// screen coordinates. +//============================================================================= + +void CToS(RECT *r) +{ +POINT pt; + +// +// Sort out the top, lefthand corner of the rectangle. +// + +pt.x = r->left; +pt.y = r->top; +VDMConsoleOperation(VDM_CLIENT_TO_SCREEN,(LPVOID)&pt); +r->left = pt.x; +r->top = pt.y; + +// +// Now do the bottom, right hand corner. +// + +pt.x = r->right; +pt.y = r->bottom; +VDMConsoleOperation(VDM_CLIENT_TO_SCREEN,(LPVOID)&pt); +r->right = pt.x; +r->bottom = pt.y; +} + + +//============================================================================= +// +// Function - EmulateCoordinates. +// Purpose - When the mouse is hidden by the user in windowed mode, this +// function generate absolute x,y values from the relative motion +// of the system pointer between mouse hardware interrupts +// +// Returns - Nothing. +// +// +// +// Author - Andrew Watson. +// Date - 19-Mar-1994. +// +//============================================================================= + +void EmulateCoordinates(half_word video_mode,IS16 move_x,IS16 move_y,IS16 *x,IS16 *y) +{ +static IS16 lastinternalX=0,lastinternalY=0; +IS16 internalX,internalY; + +// +// If the application has reset the mouse, set the x,y position to +// the centre of the default virtual screen for the current video mode. +// + + +if(bFunctionZeroReset) + { + // + // Calculate the centre of the default virtual screen + // and set the current generated coordinates to it. + // + + internalX = (VirtualX >> 1) - 1; + internalY = (VirtualY >> 1) - 1; + + bFunctionZeroReset = FALSE; + } +else if(bFunctionFour) + { + // + // The application has set the pointer to a new location. + // Tell the counter emulation about this. + // + + internalX = newF4x; + internalY = newF4y; + + // + // Don't come in here again until the next function 4. + // + + bFunctionFour = FALSE; + } +else + { + // + // Generate the new x,y position based on the counter change and + // clip to whatever boundary (default or application imposed) has + // been selected. + // + + internalX = lastinternalX + move_x; + internalY = lastinternalY + move_y; + LimitCoordinates(video_mode,&internalX,&internalY); + } + +// +// Set up the current emulated position for next time through +// this function. +// + +lastinternalX = internalX; +lastinternalY = internalY; + +// +// set up the return x,y values. +// + +*x = internalX; +*y = internalY; +} + +//============================================================================= +// Function which hooks into the base mechanism for dealing with int 33h and +// catches the function (AX=0xf) when the application tries to set the default +// mickey to pixel ratio. +//============================================================================= + +void host_m2p_ratio(word *a, word *b, word *CX, word *DX) +{ +m2pX = *(short *)CX; +m2pY = *(short *)DX; +} + + +//============================================================================= +// +// Function - WarpSystem Pointer +// Purpose - Allows movement vectors to be calculated from the movement of +// the operating system pointer. This function will not let the +// the system pointer move out of the client area. This, plus the +// warping mechanism ensures that the emulated pointer can move +// forever in any given direction. +// +// Returns - TRUE if the system pointer has moved, FALSE if not. +// +// +// +// Author - Andrew Watson. +// Date - 19-Mar-1994. +// +//============================================================================= + +BOOL WarpSystemPointer(IS16 *move_x,IS16 *move_y) +{ +POINT pt; + +// +// Is the Console window in the same place or changed +// Update the client rect data accordingly +// + +HasConsoleClientRectChanged(); + +// +// Get the current position of the system pointer +// + +GetCursorPos(&pt); + + +// +// How far has the system pointer moved since the last call. +// + +*move_x = (IS16)(pt.x - pLast.x); +*move_y = (IS16)(pt.y - pLast.y); + +// +// Do a fast exit if no movement has been determined. +// + +if(*move_x || *move_y) + { + + // + // The system mouse pointer has moved. + // See if the pointer has reached the client area boundary(s) + // + + if(pt.y <= WarpBorderRect.top || pt.y >= WarpBorderRect.bottom || + pt.x >= WarpBorderRect.right || pt.x <= WarpBorderRect.left) + { + // + // if the boundary(s) was/were met, warp the pointer to the + // client area centre. + // + + SetCursorPos((int)pMiddle.x,(int)pMiddle.y); + + // + // The current position is now the centre of the client rectangle. + // Save this as the counter delta start point for next time. + // + + pLast = pMiddle; + } + else + { + // + // There wasn't a warp. + // Update the last known position data for next time through. + // + + pLast = pt; + } + // + // The cursor has to moved as determined from the previous and current + // system pointer positions. + // + + return TRUE; + } +// +// No movement, so return appropriately. +// + +return FALSE; +} + +//============================================================================== +// Function to detect if the Console window has moved/resized. If it has, this +// function updates the WarpBorderRect and the pMiddle structures to reflect +// this. +// +// Returns TRUE if moved/resized, FALSE if not. +//============================================================================== + +BOOL HasConsoleClientRectChanged(void) +{ +RECT tR; + +// +// If console client rectangle has changed, reset the mouse clipping +// else nothing to do! +// +VDMConsoleOperation(VDM_CLIENT_RECT,&tR); + +if (tR.top != WarpClientRect.top || + tR.bottom != WarpClientRect.bottom || + tR.right != WarpClientRect.right || + tR.left != WarpClientRect.left) + { + CToS(&tR); + +#ifdef MONITOR + // + // Is the warp region an Icon in fullscreen graphics? + // Note: An icon has a client rect of 36 x 36 pixels. + // + + if((tR.right - tR.left) == 36 && (tR.bottom - tR.top) == 36) + { + // + // Make the warp region the same size as the selected buffer. + // The warp rectangle is thus originated about the top, left + // hand corner of the screen. + // + + tR.top = 0; + tR.bottom = mouse_buffer_height; + tR.left = 0; + tR.right = mouse_buffer_width; + CToS(&tR); + } +#endif //MONITOR + + // + // Clip the pointer to the new client rectangle, and retrive + // the new clipping borders. + // + ClipCursor(&tR); + GetClipCursor(&WarpBorderRect); + + // + // Note: LowerRight clip point is exclusive, UpperLeft point is inclusive + // + WarpBorderRect.right--; + WarpBorderRect.bottom--; + + + + // + // determine the middle point in the new client rectangle + // + + pMiddle.x = ((WarpBorderRect.right - WarpBorderRect.left)>>1) + +WarpBorderRect.left; + pMiddle.y = ((WarpBorderRect.bottom - WarpBorderRect.top)>>1) + +WarpBorderRect.top; + return TRUE; + } + +return FALSE; +} + +//============================================================================== +// Focus sensing routines for the pointer clipping system. Focus events come +// via the main event loop where the following two modules are called. If +// the application is using int33hf11, this is detected, and on focus gain or +// loss, the routines clip or unclip the pointer to the console window. +//============================================================================== + +void MouseInFocus(void) +{ +MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + +// +// only do when app. uses int33hf11 +// + +if(!bPointerOff) + return; +MovePointerToWindowCentre(); + +// +// Lose system pointer image again +// + +ShowConsoleCursor(sc.ActiveOutputBufferHandle, FALSE); +} + +void MouseOutOfFocus(void) +{ +// +// only do when app. uses int33hf11 +// + +if(!bPointerOff) + { + MouseDetachMenuItem(FALSE); + return; + } + +// +// Clip the pointer to the whole world (but leave its mother alone) +// + +ClipCursor(NULL); + +// +// Re-enable system pointer image +// + +ShowConsoleCursor(sc.ActiveOutputBufferHandle, TRUE); +} + +/* system memu active, stop cursor clipping */ +void MouseSystemMenuON (void) +{ + if (bPointerOff) + ClipCursor(NULL); +} +/* system menu off, restore clipping */ +void MouseSystemMenuOFF(void) +{ + if (bPointerOff) + ClipCursor(&WarpBorderRect); +} +void ResetMouseOnBlock(void) +{ +host_ica_lock(); + +os_pointer_data.x=0; +os_pointer_data.y=0; + +host_ica_unlock(); +} +#ifdef X86GFX + +//============================================================================ +// Function which is called from the 32 bit side (x86 only) when there is +// a transition from fullscreen text to windowed text. The function restores +// the background to the last mouse pointer position. This stops a pointer +// block from remaining in the image, corrupting the display when the system +// pointer is being used. +// +// This function looks into the 16 bit driver's space and points to 4, 16 bit +// words of data from it, viz: +// +// dw offset of pointer into video buffer. +// dw unused. +// dw image data to be restored. +// dw flag = 0 if the background is stored +// +// Note: that during a fullscreen switch, 16 bit code cannot be executed, +// thus the patching of the buffer is done here. +//============================================================================ + +void CleanUpMousePointer() +{ +half_word vm; + +// +// Only execute this routine fully if in TEXT mode +// + +sas_load(0x449,&vm); // Get the current video mode according to the B.D.A. + +if(TextOrGraphicsModeLUT[(int)vm] != TEXT_MODE) + return; + +// +// If there is a backround stored for the text pointer when it was +// in fullscreen land, then restore it to the place it came from +// when windowed. +// + +if(bFullscTextBkgrndSaved) + { + sas_storew(old_text_addr,text_ptr_bkgrnd); + + // + // No background saved now. + // + + bFullscTextBkgrndSaved = FALSE; + } +} + +#endif //X86GFX + +//=========================================================================== +// Function to display the text cursor image for fullscreen text mode. +// INPUT: x,y pointer virtual cartesian coordinates for text screen buffer. +// Note: the Y coordinates are received in the sequence 0, 8, 16, 24, 32, ... +// since a virtual text cell is 8 virtual pixels square. +//=========================================================================== + + +void FullscTextPtr(int x,int y) +{ +#ifdef X86GFX +sys_addr text_addr; +word current_display_page; + +// +// Work out the offset to the current video display page. +// Grovel around the B.D.A. to find out where the page starts. +// + +sas_loadw(effective_addr(0x40,0x4e),¤t_display_page); +x = (int)((DWORD)x & 0xFFFFFFF8); +y = (int)((DWORD)y & 0xFFFFFFF8); + +// +// save the character cell behind the next pointer +// Note: The text cell offset calculated below is based on +// the following concepts: +// The virtual character cell size is 8 x 8 virtual pixels. +// The input data to this function is in virtual pixels. +// There are 80 text cells in a row = 80 (CHAR:ATTR) words. +// The >>3<<1 on the x value ensures that the location +// in the buffer to be modified occurs on a word boundary to +// get the masking correct! +// + +x &= 0xfffc; // remove the top to prevent funny shifts. +x >>= 2; // get the word address for the current row +y &= 0xffff; // work out the total number of locations for all the y rows +y *= 20; // + +// +// Generate the address in the display buffer at which the pointer +// should be drawn. +// + +text_addr = effective_addr(0xb800,(word)(current_display_page + x + y)); // assemble the cell address + +// +// only restore the background if there is a background to restore! +// + +if(bFullscTextBkgrndSaved) + { + sas_storew(old_text_addr,text_ptr_bkgrnd); + } + +// +// Load up the background from the new address +// + +sas_loadw(text_addr,&text_ptr_bkgrnd); // read from that place +bFullscTextBkgrndSaved=TRUE; + +// +// Write the pointer to the video buffer. +// Use some standard masks and forget what the app wants to +// do cos that really isn't important and it's slow plus not +// very many apps want to change the text pointer shape anyway. +// + +sas_storew(text_addr,(word)((text_ptr_bkgrnd & 0x77ff) ^ 0x7700)); + +// +// save the static variables to be used next time through the routine +// + +old_text_addr=text_addr; + +#endif // X86GFX +} + +//============================================================================== +// Function to get the maximum and minimum possible virtual pixel locations +// in X as requested by the application through int 33h function 7. +//============================================================================== + +void host_x_range(word *blah, word *blah2,word *CX,word *DX) +{ +confine.bF7 = TRUE; +confine.xmin = *CX; +confine.xmax = *DX; + +// +// Force a mouse interrupt to make it happen. +// + + LazyMouseInterrupt(); +} + +//============================================================================== +// Function to get the maximum and minimum possible virtual pixel locations +// in Y as requested by the application through int 33h function 8. +//============================================================================== + +void host_y_range(word *blah, word *blah2,word *CX,word *DX) +{ +confine.bF8 = TRUE; +confine.ymin = *CX; +confine.ymax = *DX; + +// +// Force a mouse interrupt to make it happen. +// + + LazyMouseInterrupt(); +} + + + +/* + * LazyMouseInterrupt - + * + */ +void LazyMouseInterrupt(void) +{ + host_ica_lock(); + if (!bMseEoiPending && !bSuspendMouseInterrupts) { + if (MseIntLazyCount) + MseIntLazyCount--; + bMseEoiPending = TRUE; + ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT,1); + HostIdleNoActivity(); + } + else if (!MseIntLazyCount) { + MseIntLazyCount++; + } + host_ica_unlock(); +} + + +/* SuspendMouseInterrupts + * + * Prevents Mouse Interrupts from occuring until + * ResumeMouseInterrupts is called + * + */ +void SuspendMouseInterrupts(void) +{ + host_ica_lock(); + bSuspendMouseInterrupts = TRUE; + host_ica_unlock(); +} + + +/* + * ResumeMouseInterrupts + * + */ +void ResumeMouseInterrupts(void) +{ + host_ica_lock(); + bSuspendMouseInterrupts = FALSE; + + if (!bMseEoiPending && + (MseIntLazyCount || MoreMouseEvents()) ) + { + if (MseIntLazyCount) + MseIntLazyCount--; + bMseEoiPending = TRUE; + host_DelayHwInterrupt(9, // AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT + 1, // count + 10000 // Delay + ); + HostIdleNoActivity(); + } + + host_ica_unlock(); +} + + + +/* + * DoMouseInterrupt, assumes we are holding the ica lock + * + */ +void DoMouseInterrupt(void) +{ + + if (bMseEoiPending || bSuspendMouseInterrupts) { + MseIntLazyCount++; + return; + } + + if (MseIntLazyCount) + MseIntLazyCount--; + bMseEoiPending = TRUE; + ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT,1); + HostIdleNoActivity(); +} + + +/* + * MouseEoiHook, assumes we are holding the ica lock + * + */ +VOID MouseEoiHook(int IrqLine, int CallCount) +{ + + if (CallCount < 0) { // interrupts were cancelled + MseIntLazyCount = 0; + FlushMouseEvents(); + bMseEoiPending = FALSE; + return; + } + + if (!bSuspendMouseInterrupts && + (MseIntLazyCount || MoreMouseEvents())) + { + if (MseIntLazyCount) + MseIntLazyCount--; + bMseEoiPending = TRUE; + host_DelayHwInterrupt(9, // AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT + 1, // count + 10000 // Delay usecs + ); + HostIdleNoActivity(); + } + else { + bMseEoiPending = FALSE; + } +} diff --git a/private/mvdm/softpc.new/host/src/nt_msscs.c b/private/mvdm/softpc.new/host/src/nt_msscs.c new file mode 100644 index 000000000..d9286056a --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_msscs.c @@ -0,0 +1,1416 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdmapi.h> +#include <vdm.h> +#include "insignia.h" +#include "host_def.h" +#include "conapi.h" +#include "ctype.h" +#include "stdlib.h" +#include "stdio.h" +#include "string.h" +#include <io.h> +#include <fcntl.h> + +#include "xt.h" +#include CpuH +#include "error.h" +#include "sas.h" +#include "ios.h" +#include "umb.h" +#include "gvi.h" +#include "sim32.h" +#include "bios.h" + +#include "nt_eoi.h" +#include "nt_uis.h" +#include "nt_event.h" +#include "nt_graph.h" +#include "nt_event.h" +#include "nt_reset.h" +#include "config.h" +#include <nt_vdd.h> // DO NOT USE vddsvc.h +#include <nt_vddp.h> +#include <host_emm.h> +#include "emm.h" +#include <demexp.h> +#include <vint.h> + +PMEM_HOOK_DATA MemHookHead = NULL; +PVDD_USER_HANDLERS UserHookHead= NULL; + +extern BOOL CMDInit (int argc,char *argv[]); +extern BOOL XMSInit (int argc,char *argv[]); +extern BOOL DBGInit (int argc,char *argv[]); +extern DWORD TlsDirectError; +extern VOID FloppyTerminatePDB(USHORT PDB); +extern VOID FdiskTerminatePDB(USHORT PDB); + +// internal function prototypes +VOID SetupInstallableVDD (VOID); +void AddSystemFiles(void); + +void scs_init(int argc, char **argv) +{ + PSZ psz; + BOOL IsFirst; + + IsFirst = GetNextVDMCommand(NULL); + if (IsFirst) { + AddSystemFiles(); + } + + // Initialize SCS + + CMDInit (argc,argv); + + // Initialize DOSEm + + if(!DemInit (argc,argv)) { + host_error(EG_OWNUP, ERR_QUIT, "NTVDM:DemInit fails"); + TerminateVDM(); + } + + // Initialize XMS + + if(!XMSInit (argc,argv)) { + host_error(EG_OWNUP, ERR_QUIT, "NTVDM:XMSInit fails"); + TerminateVDM(); + } + + // Initialize DBG + + if(!DBGInit (argc,argv)) { +#ifndef PROD + printf("NTVDM:DBGInit fails\n"); + HostDebugBreak(); +#endif + TerminateVDM(); + } +} + +// +// This routine contains the Dos Emulation initialisation code, called from +// main(). We currently do not support container files. +// + + +InitialiseDosEmulation(int argc, char **argv) +{ + HANDLE hFile; + DWORD FileSize; + DWORD BytesRead; + DWORD dw; + ULONG fVirtualInt; + host_addr pDOSAddr; + CHAR buffer[MAX_PATH*2]; +#ifdef LIM + LIM_CONFIG_DATA lim_config_data; +#endif + + // + // first order of bussiness, initialize virtual interrupt flag in + // dos arena. this has to be done here before it gets changed + // by reading in ntio.sys + // + + sas_loads((ULONG)FIXED_NTVDMSTATE_LINEAR, + (PCHAR)&fVirtualInt, + FIXED_NTVDMSTATE_SIZE + ); +#ifndef i386 + fVirtualInt |= MIPS_BIT_MASK; +#else + fVirtualInt &= ~MIPS_BIT_MASK; +#endif + sas_storedw((ULONG)FIXED_NTVDMSTATE_LINEAR,fVirtualInt); + + io_init(); + + // + // Allocate per thread local storage. + // Currently we only need to store one DWORD, so we + // don't need any per thread memory. + // + TlsDirectError = TlsAlloc(); +#ifndef PROD + if (TlsDirectError == 0xFFFFFFFF) + printf("NTVDM: TlsDirectError==0xFFFFFFFF GLE=%ld\n", GetLastError); +#endif + + + // SetupInstallableVDD (); + + /*................................................... Execute reset */ + reset(); + + SetupInstallableVDD (); + /* reserve lim block after all vdd are installed. + the pif file settings tell us if it is necessary to + reserve the block + */ + +#ifdef LIM + /* initialize lim page frames after all vdd are installed. + the pif file settings tell us if it is necessary to + reserve the block. + */ + if (get_lim_configuration_data(&lim_config_data)) + lim_page_frame_init(&lim_config_data); + +#endif + + scs_init(argc, argv); // Initialise single command shell + + /*................................................. Load DOSEM code */ + + dw = GetSystemDirectory(buffer, sizeof(buffer)); + if (!dw || dw >= sizeof(buffer)) { + host_error(EG_OWNUP, ERR_QUIT, "NTVDM:InitialiseDosEmulation fails"); + TerminateVDM(); + } + + strcat(buffer, "\\ntio.sys"); + + hFile = CreateFile(buffer, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (hFile == INVALID_HANDLE_VALUE || + !(FileSize = GetFileSize(hFile, &BytesRead)) || + BytesRead ) + { +#ifndef PROD + printf("NTVDM:Fatal Error, Invalid file or missing - %s\n",buffer); +#endif + host_error(EG_SYS_MISSING_FILE, ERR_QUIT, buffer); + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + } + return (-1); + } + + + pDOSAddr = get_byte_addr(((NTIO_LOAD_SEGMENT<<4)+NTIO_LOAD_OFFSET)); + + if (!ReadFile(hFile, pDOSAddr, FileSize, &BytesRead, NULL) || + FileSize != BytesRead) + { + +#ifndef PROD + printf("NTVDM:Fatal Error, Read file error - %s\n",buffer); +#endif + host_error(EG_SYS_MISSING_FILE, ERR_QUIT, buffer); + CloseHandle(hFile); + return (-1); + } + + CloseHandle(hFile); + + // oops ... restore the virtual interrupt state, + // which we just overwrote in the file read, and reset. + sas_storedw((ULONG)FIXED_NTVDMSTATE_LINEAR, fVirtualInt); + + setCS(NTIO_LOAD_SEGMENT); + setIP(NTIO_LOAD_OFFSET); // Start CPU at DosEm initialisation entry point + + + // + // Ensure that WOW VDM runs at NORMAL priorty + // + if (VDMForWOW) { + SetPriorityClass (NtCurrentProcess(), NORMAL_PRIORITY_CLASS); + } + + // + // Don't allow dos vdm to run at realtime + // + else if (GetPriorityClass(NtCurrentProcess()) == REALTIME_PRIORITY_CLASS) + { + SetPriorityClass(NtCurrentProcess(), HIGH_PRIORITY_CLASS); + } + + + return 0; +} + + +/* + * AddSystemFiles + * + * If the system file IBMDOS.SYS|MSDOS.SYS doesn't exist + * in the root of c: create zero len MSDOS.SYS + * + * If the system file IO.SYS does not exist create + * a zero len IO.SYS + * + * This hack is put in especially for the Brief 3.1 install + * program which looks for the system files, and if they are + * not found screws up the config.sys file. + * + */ +void AddSystemFiles(void) +{ + HANDLE hFile, hFind; + WIN32_FIND_DATA wfd; + char *pchIOSYS ="C:\\IO.SYS"; + char *pchMSDOSSYS ="C:\\MSDOS.SYS"; + + + hFind = FindFirstFile(pchMSDOSSYS, &wfd); + if (hFind == INVALID_HANDLE_VALUE) { + hFind = FindFirstFile("C:\\IBMDOS.SYS", &wfd); + } + + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + } + else { + hFile = CreateFile(pchMSDOSSYS, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_READONLY, + 0); + if (hFile != INVALID_HANDLE_VALUE) { // not much we can do if fails + CloseHandle(hFile); + } + + } + + hFind = FindFirstFile(pchIOSYS, &wfd); + if (hFind == INVALID_HANDLE_VALUE) { + hFind = FindFirstFile("C:\\IBMBIO.SYS", &wfd); + } + + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + } + else { + hFile = CreateFile(pchIOSYS, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_READONLY, + 0); + if (hFile != INVALID_HANDLE_VALUE) { // not much we can do if fails + CloseHandle(hFile); + } + + } +} + + +#ifdef LIM +/* parse EMM= line in config.nt to collect EMM parameters. The EMM line has + * the following syntax: + * EMM=[a=altregs][b=segment][i=segment1-segment2][x=segment1-segment2] [RAM] + * where "a=altregs" specifies how many alternative mapping register set + * "b=segment" specifies the backfill starting segment address. + * "RAM" indicates that the system should only allocate 64KB from + * UMB to use as EMM page frame. + * "i=segment1 - segment2" specifies a particular range of + * address that the system should include as EMM page frame + * "x=segment1 - segment2" specifies a particular range of + * address that the system should NOT use as page frame. + * + * input: pointer to LIM_PARAMS + * output: LIM_PARAMS is filled with data + * + */ + +#define IS_EOL_CHAR(c) (c == '\n' || c == '\r' || c == '\0') +#define SKIP_WHITE_CHARS(size, ptr) while (size && isspace(*ptr)) \ + { ptr++; size--; } + +#define TOINT(c) ((c >= '0' && c <= '9') ? (c - '0') : \ + ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) : \ + ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0) \ + )\ + ) + +boolean init_lim_configuration_data(PLIM_CONFIG_DATA lim_data) +{ + char config_sys_pathname[MAX_PATH]; + HANDLE handle; + DWORD file_size, bytes_read, size; + char *buffer, *ptr; + short lim_size, base_segment, total_altreg_sets; + boolean ram_flag_found, reserve_umb_status, parsing_error; + sys_addr page_frame; + int i; + + + /* initialize some default values */ + base_segment = 0x4000; + total_altreg_sets = 8; + ram_flag_found = FALSE; + + parsing_error = FALSE; + + /* if we can not find config.nt, we can not go on */ + GetPIFConfigFiles(TRUE, config_sys_pathname); + if (*config_sys_pathname == '\0') + return FALSE; + + handle = CreateFile(config_sys_pathname, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + + file_size = GetFileSize(handle, NULL); + if (file_size == 0 || file_size == 0xFFFFFFFF) { + CloseHandle(handle); + return FALSE; + } + buffer = malloc(file_size); + if (buffer == NULL) { + CloseHandle(handle); + host_error(EG_MALLOC_FAILURE, ERR_QUIT, ""); + return FALSE; + } + if (!ReadFile(handle, buffer, file_size, &bytes_read, NULL) || + bytes_read != file_size) + { + CloseHandle(handle); + free(buffer); + return FALSE; + } + CloseHandle(handle); + + ptr = buffer; + + while(file_size) { + /* skip leading white characters on each line */ + SKIP_WHITE_CHARS(file_size, ptr); + /* nothing meaningful in the file, break */ + if (!file_size) + break; + /* looking for EMM */ + if (file_size < 3 || toupper(ptr[0]) != 'E' || + toupper(ptr[1]) != 'M' || toupper(ptr[2]) != 'M') + { + /* we don't want this line, skip it by looking for the first EOL + * char in the line + */ + do { + file_size--; + ptr++; + } while(file_size && !IS_EOL_CHAR(*ptr)); + + /* either there are nothing left in the file or we have EOL + * char(s) in the line, loop through to skip all consecutive + * EOL char(s) + */ + while(file_size && IS_EOL_CHAR(*ptr)) { + file_size--; + ptr++; + } + } + else { + /* got "EMM", looking for '=' */ + file_size -= 3; + ptr += 3; + SKIP_WHITE_CHARS(file_size, ptr); + if (!file_size || *ptr != '=') + parsing_error = TRUE; + else { + file_size--; + ptr++; + SKIP_WHITE_CHARS(file_size, ptr); + /* "EMM=" is a valid EMM command line */ + } + break; + } + } + /* we have three possibilities here: + * (1). we found pasring error while we were looking for "EMM=" + * (2). no "EMM=" line was found + * (3). "EMM=" was found and ptr points to the first nonwhite + * char after '='. + */ + while (file_size && !parsing_error && !IS_EOL_CHAR(*ptr)) { + SKIP_WHITE_CHARS(file_size, ptr); + switch (*ptr) { + case 'a': + case 'A': + + /* no white chars allowed between 'a' and its + * parameter + */ + if (!(--file_size) || *(++ptr) != '='){ + parsing_error = TRUE; + break; + } + file_size--; + ptr++; + /* about to parsing 'a=' switch, reset the preset value to 0 */ + total_altreg_sets = 0; + + while(file_size && isdigit(*ptr)) { + total_altreg_sets = total_altreg_sets * 10 + (*ptr - '0'); + file_size--; + ptr++; + if (total_altreg_sets > 255) { + parsing_error = TRUE; + break; + } + } + if (!total_altreg_sets || total_altreg_sets > 255) + parsing_error = TRUE; + break; + + case 'b': + case 'B': + /* no white chars allowed between 'b' and its + * parameter + */ + if (!(--file_size) || *(++ptr) != '='){ + parsing_error = TRUE; + break; + } + file_size--; + ptr++; + base_segment = 0; + while(file_size && isxdigit(*ptr)) { + base_segment = (base_segment << 4) + TOINT(*ptr); + file_size--; + ptr++; + if (base_segment > 0x4000) { + parsing_error = TRUE; + break; + } + } + /* x01000 <= base_segment <= 0x4000 */ + + if (base_segment >= 0x1000 && base_segment <= 0x4000) + /* round down the segment to EMM_PAGE_SIZE boundary */ + base_segment = ((((ULONG)base_segment * 16) / EMM_PAGE_SIZE) + * EMM_PAGE_SIZE) / 16; + else + parsing_error = TRUE; + break; + + case 'r': + case 'R': + if (file_size >= 3 && + (ptr[1] == 'a' || ptr[1] == 'A') && + (ptr[2] == 'm' || ptr[2] == 'M')) + { + file_size -= 3; + ptr += 3; + ram_flag_found = TRUE; + break; + } + /* fall through if it is not RAM */ + + default: + parsing_error = TRUE; + break; + } /* switch */ + + } /* while */ + + free(buffer); + if (parsing_error) { + host_error(EG_BAD_EMM_LINE, ERR_QUIT, ""); + /* reset parameters because the emm command line is not reliable */ + base_segment = 0x4000; + total_altreg_sets = 8; + ram_flag_found = FALSE; + } + + /* we got here if (1). no parsing error or (2). user opted to ignore + * the parsing error + */ + + lim_data->total_altreg_sets = total_altreg_sets; + + lim_data->backfill = (640 * 1024) - (base_segment * 16); + + lim_data->base_segment = base_segment; + lim_data->use_all_umb = !ram_flag_found; + +#ifdef EMM_DEBUG + printf("base segment=%x, backfill =%lx; altreg sets=%d\n", + base_segment, lim_data->backfill, total_altreg_sets); +#endif + + return TRUE; +} + +unsigned short get_lim_page_frames(USHORT * page_table, + PLIM_CONFIG_DATA lim_data + ) +{ + + USHORT total_phys_pages, base_segment, i; + BOOL reserve_umb_status; + ULONG page_frame, size; + + /* we search for the primary EMM page frame first from 0xE0000. + * if we can not find it there, then look for anywhere in UMB area. + * if the primary EMM page frame is found, and RAM is not specified, + * collect every possible page frame in the UMB. + * if RAM has been specified, only allocate the primary page frame. + */ + total_phys_pages = 0; + base_segment = lim_data->base_segment; + reserve_umb_status = FALSE; + + /* specificaly ask for 0xE0000 */ + page_frame = 0xE0000; + /* primary page frames are always EMM_PAGE_SIZE * 4 */ + size = EMM_PAGE_SIZE * 4; + reserve_umb_status = ReserveUMB(UMB_OWNER_EMM, (PVOID *)&page_frame, &size); + /* if failed to find the primary page frame at 0xE0000, search for anywhere + * available in the UMB area + */ + if (!reserve_umb_status) { + page_frame = 0; + size = 0x10000; + reserve_umb_status = ReserveUMB(UMB_OWNER_EMM, (PVOID *)&page_frame, &size); + } + if (!reserve_umb_status) { +#ifdef EMM_DEBUG + printf("couldn't find primary page frame\n"); +#endif + return FALSE; + } + page_table[0] = (short)(page_frame / 16); + page_table[1] = (short)((page_frame + 1 * EMM_PAGE_SIZE) / 16); + page_table[2] = (short)((page_frame + 2 * EMM_PAGE_SIZE) / 16); + page_table[3] = (short)((page_frame + 3 * EMM_PAGE_SIZE) / 16); + + + total_phys_pages = 4; + + /* now add back fill page frames */ + for (i = lim_data->backfill / EMM_PAGE_SIZE; i != 0 ; i--) { + page_table[total_phys_pages++] = base_segment; + base_segment += EMM_PAGE_SIZE / 16; + } + + /* RAM is not specified in the command line, grab every possible + * page frame from UMB + */ + if (lim_data->use_all_umb) { + while (TRUE) { + page_frame = 0; + size = EMM_PAGE_SIZE; + if (ReserveUMB(UMB_OWNER_EMM, (PVOID *)&page_frame, &size)) + page_table[total_phys_pages++] = (short)(page_frame / 16); + else + break; + } + } + +#ifdef EMM_DEBUG + printf("page frames:\n"); + for (i = 0; i < total_phys_pages; i++) + printf("page number %d, segment %x\n",i, page_table[i]); +#endif + return total_phys_pages; +} +#endif /* LIM */ + + +VOID SetupInstallableVDD (VOID) +{ +HANDLE hVDD; +HKEY VDDKey; +CHAR szClass [MAX_CLASS_LEN]; +DWORD dwClassLen = MAX_CLASS_LEN; +DWORD nKeys,cbMaxKey,cbMaxClass,nValues=0,cbMaxValueName,cbMaxValueData,dwSec; +DWORD dwType; +PCHAR pszName,pszValue; +FILETIME ft; +PCHAR pKeyName = "SYSTEM\\CurrentControlSet\\Control\\VirtualDeviceDrivers"; + + if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, + pKeyName, + 0, + KEY_QUERY_VALUE, + &VDDKey + ) != ERROR_SUCCESS){ + RcErrorDialogBox(ED_REGVDD, pKeyName, NULL); + return; + } + + pszName = "VDD"; + + // get size of VDD value + if (RegQueryInfoKey (VDDKey, + (LPTSTR)szClass, + &dwClassLen, + NULL, + &nKeys, + &cbMaxKey, + &cbMaxClass, + &nValues, + &cbMaxValueName, + &cbMaxValueData, + &dwSec, + &ft + ) != ERROR_SUCCESS) { + RcErrorDialogBox(ED_REGVDD, pKeyName, pszName); + RegCloseKey (VDDKey); + return; + } + + + // alloc temp memory for the VDD value (multi-string) + if ((pszValue = (PCHAR) malloc (cbMaxValueData)) == NULL) { + RcErrorDialogBox(ED_MEMORYVDD, pKeyName, pszName); + RegCloseKey (VDDKey); + return; + } + + + // finally get the VDD value (multi-string) + if (RegQueryValueEx (VDDKey, + (LPTSTR)pszName, + NULL, + &dwType, + (LPBYTE)pszValue, + &cbMaxValueData + ) != ERROR_SUCCESS || dwType != REG_MULTI_SZ) { + RcErrorDialogBox(ED_REGVDD, pKeyName, pszName); + RegCloseKey (VDDKey); + free (pszValue); + return; + } + + pszName = pszValue; + + while (*pszValue) { + if ((hVDD = SafeLoadLibrary(pszValue)) == NULL){ + RcErrorDialogBox(ED_LOADVDD, pszValue, NULL); + } + pszValue =(PCHAR)strchr (pszValue,'\0') + 1; + } + + RegCloseKey (VDDKey); + free (pszName); + return; +} + +/*** VDDInstallMemoryHook - This service is provided for VDDs to hook the + * Memory Mapped IO addresses they are resposible + * for. + * + * INPUT: + * hVDD : VDD Handle + * addr : Starting linear address + * count : Number of bytes + * MemoryHandler : VDD handler for the memory addresses + * + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * NOTES + * 1. The first one to hook an address will get the control. There + * is no concept of chaining the hooks. VDD should grab the + * memory range in its initialization routine. After all + * the VDDs are loaded, EMM will eat up all the remaining + * memory ranges for UMB support. + * + * 2. Memory handler will be called with the address on which the + * page fault occured. It wont say whether it was a read operation + * or write operation or what were the operand value. If a VDD + * is interested in such information it has to get the CS:IP and + * decode the instruction. + * + * 3. On returning from the hook handler it will be assumed that + * the page fault was handled and the return will go back to the + * VDM. + * + * 4. Installing a hook on a memory range will result in the + * consumption of memory based upon page boundaries. The Starting + * address is rounded down, and the count is rounded up to the + * next page boundary. The VDD's memory hook handler will be + * invoked for all addreses within the page(s) hooked. The page(s) + * will be set aside as mapped reserved sections, and will no + * longer be available for use by NTVDM or other VDDs. The VDD is + * permitted to manipulate the memory (commit, free, etc) as needed. + * + * 5. After calling the MemoryHandler, NTVDM will return to the + * faulting cs:ip in the 16bit app. If the VDD does'nt want + * that to happen it should adjust cs:ip appropriatly by using + * setCS and setIP. + */ + +BOOL VDDInstallMemoryHook ( + HANDLE hVDD, + PVOID pStart, + DWORD count, + PVDD_MEMORY_HANDLER MemoryHandler + ) +{ +PMEM_HOOK_DATA pmh = MemHookHead,pmhNew,pmhLast=NULL; + + DWORD dwStart; + + + if (count == 0 || pStart == (PVOID)NULL || count > 0x20000) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + + if (dwStart < 0xC0000) { + SetLastError (ERROR_ACCESS_DENIED); + return FALSE; + } + + while (pmh) { + // the requested block can never be overlapped with any other + // existing blocks + if(dwStart >= pmh->StartAddr + pmh->Count || + dwStart + count <= pmh->StartAddr){ + pmhLast = pmh; + pmh = pmh->next; + continue; + } + + // failure case + SetLastError (ERROR_ACCESS_DENIED); + return FALSE; + } + if ((pmhNew = (PMEM_HOOK_DATA) malloc (sizeof(MEM_HOOK_DATA))) == NULL) { + SetLastError (ERROR_OUTOFMEMORY); + return FALSE; + } + // the request block is not overlapped with existing blocks, + // request the UMB managing function to allocate the block + if (!ReserveUMB(UMB_OWNER_VDD, (PVOID *)&dwStart, &count)) { + free(pmhNew); + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + // now set up the new node to get to know it + pmhNew->Count = count; + pmhNew->StartAddr = dwStart; + pmhNew->hvdd = hVDD; + pmhNew->MemHandler = MemoryHandler; + pmhNew->next = NULL; + + // Check if the record is to be added in the begining + if (MemHookHead == NULL || pmhLast == NULL) { + MemHookHead = pmhNew; + return TRUE; + } + + pmhLast->next = pmhNew; + return TRUE; +} + +/*** VDDDeInstallMemoryHook - This service is provided for VDDs to unhook the + * Memory Mapped IO addresses. + * + * INPUT: + * hVDD : VDD Handle + * addr : Starting linear address + * count : Number of addresses + * + * OUTPUT + * None + * + * NOTES + * 1. On Deinstalling a hook, the memory range becomes invalid. + * VDM's access of this memory range will cause a page fault. + * + */ + +BOOL VDDDeInstallMemoryHook ( + HANDLE hVDD, + PVOID pStart, + DWORD count + ) +{ +PMEM_HOOK_DATA pmh = MemHookHead,pmhLast=NULL; + + DWORD dwStart; + + if (count == 0 || pStart == (PVOID)NULL || count > 0x20000) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + while (pmh) { + if (pmh->hvdd == hVDD && + pmh->StartAddr == dwStart && + pmh->Count == count ) { + if (pmhLast) + pmhLast->next = pmh->next; + else + MemHookHead = pmh->next; + + // free the UMB for other purpose. + // Note that VDDs may have committed memory for their memory + // hook and forgot to decommit the memory before calling + // this function. If that is the case, the ReleaseUMB will take + // care of this. It is because we want to maintain a single + // version of VDD support routines while move platform depedend + // routines into the other module. + if (ReleaseUMB(UMB_OWNER_VDD,(PVOID)dwStart, count)) { + // free the node. + free(pmh); + return TRUE; + } + else { + printf("Failed to release VDD memory\n"); + } + } + pmhLast = pmh; + pmh = pmh->next; + } + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; +} + + + +BOOL +VDDAllocMem( +HANDLE hVDD, +PVOID pStart, +DWORD count +) +{ + PMEM_HOOK_DATA pmh = MemHookHead; + DWORD dwStart; + + if (count == 0 || pStart == (PVOID)NULL || count > 0x20000) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + + while(pmh) { + if (pmh->hvdd == hVDD && + pmh->StartAddr <= dwStart && + pmh->StartAddr + pmh->Count >= dwStart + count) + return(VDDCommitUMB((PVOID)dwStart, count)); + pmh = pmh->next; + } + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; +} + + +BOOL +VDDFreeMem( +HANDLE hVDD, +PVOID pStart, +DWORD count +) +{ + PMEM_HOOK_DATA pmh = MemHookHead; + DWORD dwStart; + + + if (count == 0 || pStart == (PVOID)NULL || count > 0x20000) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + + while(pmh) { + if (pmh->hvdd == hVDD && + pmh->StartAddr <= dwStart && + pmh->StartAddr + pmh->Count >= dwStart + count) + return(VDDDeCommitUMB((PVOID)dwStart, count)); + pmh = pmh->next; + } + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; +} + + + // Will publish the following two functions someday. + // Please change ntvdm.def, nt_vdd.h and nt_umb.c + // if you remove the #if 0 +BOOL +VDDIncludeMem( +HANDLE hVDD, +PVOID pStart, +DWORD count +) +{ + DWORD dwStart; + + if (count == 0 || pStart == NULL){ + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + return(ReserveUMB(UMB_OWNER_NONE, (PVOID *) &dwStart, &count)); +} + +BOOL +VDDExcludeMem( +HANDLE hVDD, +PVOID pStart, +DWORD count +) +{ + + DWORD dwStart; + + if (count == 0 || pStart == NULL) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + // round addr down to next page boundary + // round count up to next page boundary + dwStart = (DWORD)pStart & ~(HOST_PAGE_SIZE-1); + count += (DWORD)pStart - dwStart; + count = (count + HOST_PAGE_SIZE - 1) & ~(HOST_PAGE_SIZE-1); + return(ReserveUMB(UMB_OWNER_ROM, (PVOID *) &dwStart, &count)); +} + + + +VOID +VDDTerminateVDM() +{ + TerminateVDM(); +} + +VOID DispatchPageFault ( + ULONG FaultAddr, + ULONG RWMode + ) +{ +PMEM_HOOK_DATA pmh = MemHookHead; + + // dispatch intel linear address always + FaultAddr -= (ULONG)Sim32GetVDMPointer(0, 0, FALSE); + // Find the VDD and its handler which is to be called for this fault + while (pmh) { + if (pmh->StartAddr <= FaultAddr && + FaultAddr <= (pmh->StartAddr + pmh->Count)) { + + // Call the VDD's memory hook handler + (*pmh->MemHandler) ((PVOID)FaultAddr, RWMode); + return; + } + else { + pmh = pmh->next; + continue; + } + } + + // A page fault occured on an address for which we could'nt find a + // VDD. Raise the exception. + RaiseException ((DWORD)STATUS_ACCESS_VIOLATION, + EXCEPTION_NONCONTINUABLE, + 0, + NULL); + +} + + +/** + * + * Input - TRUE means redirection is effective + * FALSE means no redirection + * + * This routine will get called after every GetNextVDMCommand i.e. + * on every DOS app that a user runs from the prompt. I think + * you can safely ignore this callout for WOW. + * + **/ +void nt_std_handle_notification (BOOL fIsRedirection) +{ + /* + ** Set global so we know when redirection is active. + */ + + stdoutRedirected = fIsRedirection; + +#ifdef X86GFX + + if( !fIsRedirection && sc.ScreenState==FULLSCREEN ) + { + half_word mode = 3, + lines = 0; + + // + // WORD 6 and other apps cause this code path to be followed + // on application startup. now if line==0, SelectMouseBuffer + // causes a 640 x 200 buffer to be selected. This is not + // correct if the app is in a 43 or 50 text line mode. + // Therefore, since the BIOS data area location 40:84 holds + // the number of rows - 1 at this point (if the app uses int 10h + // function 11 to change mode) then pick up the correct value + // from here. Andy! + + if(sc.ModeType == TEXT) + { + sas_load(0x484,&lines); + + // + // The value is pulled from the BIOS data area. + // This is one less than the number of rows. So + // increment to give SelectMouseBuffer what it + // expects. Let this function do the necessary + // handling of non 25, 43 and 50 values. + // + + lines++; + } + + SelectMouseBuffer(mode, lines); + } +#endif //X86GFX +} + +/*** VDDInstallUserHook + * + * This service is provided for VDDs to hook callback events. + * These callback events include, PDB (DOS Process) creation, PDB + * termination, VDM block and VDM resume. Whenever DOS creates ( + * for example int21/exec) or terminates (for example int21/exit) + * a 16bit process VDD could get a notification for that. A VDM in + * which a DOS app runs, is attached to the console window in which + * the DOS app is running. VDM gets created when first DOS binary + * runs in that console. When that DOS binary terminates, VDM stays + * with the console window and waits for the next DOS binary to be + * launched. When VDM is waiting for this next DOS binary all its + * components including VDDs should block. For this purpose, VDDs + * could hook VDM Block and Resume events. On Block event VDDs + * should block all their worker threads and cleanup any other + * operation they might have started. On resume they can restart + * worker threads. + * + * INPUT: + * hVDD : VDD Handle + * Ucr_handler: handle on creating function (OPTIONAL) + * Entry - 16bit DOS PDB + * EXIT - None + * Uterm_handler: handle on terminating function (OPTIONAL) + * Entry - 16bit DOS PDB + * EXIT - None + * Ublock_handler: handle on block (of ntvdm) function (OPTIONAL) + * Entry - None + * EXIT - None + * Uresume_handler: handle on resume (of ntvdm) function (OPTIONAL) + * Entry - None + * EXIT - None + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * NOTES: + * If hvdd in not valid it will return ERROR_INVALID_PARAMETER. + * VDD can provide whatever event hook they may choose. Not providing + * any handler has no effect. There are lots of requests in DOS world + * for which there is no explicit Close operation. For instance + * printing via int17h. A VDD supporting printing will never be able to + * detect when to flush the int17 characters, if its spolling them. + * But with the help of PDB create/terminate the VDD can achieve it. + */ + +BOOL VDDInstallUserHook ( + HANDLE hVDD, + PFNVDD_UCREATE Ucr_Handler, + PFNVDD_UTERMINATE Uterm_Handler, + PFNVDD_UBLOCK Ublock_handler, + PFNVDD_URESUME Uresume_handler +) +{ + PVDD_USER_HANDLERS puh = UserHookHead; + PVDD_USER_HANDLERS puhNew; + + + if (!hVDD) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if ((puhNew = (PVDD_USER_HANDLERS) malloc (sizeof(VDD_USER_HANDLERS))) == NULL) { + SetLastError (ERROR_OUTOFMEMORY); + return FALSE; + } + + // now set up the new node to get to know it + puhNew->hvdd = hVDD; + puhNew->ucr_handler = Ucr_Handler; + puhNew->uterm_handler = Uterm_Handler; + puhNew->ublock_handler = Ublock_handler; + puhNew->uresume_handler = Uresume_handler; + + // Check if the record is to be added in the begining + if (UserHookHead == NULL) { + puhNew->next = NULL; + UserHookHead = puhNew; + return TRUE; + } + + puhNew->next = UserHookHead; + UserHookHead = puhNew; + return TRUE; +} + +/*** VDDDeInstallUserHook + * + * This service is provided for VDDs to unhook callback events. + * + * INPUT: + * hVDD : VDD Handle + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * NOTES + * This service will deinstall all the events hooked earlier + * using VDDInstallUserHook. + */ + +BOOL VDDDeInstallUserHook ( + HANDLE hVDD) +{ + + PVDD_USER_HANDLERS puh = UserHookHead; + PVDD_USER_HANDLERS puhLast = NULL; + + + if (!hVDD) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + while (puh) { + if (puh->hvdd == hVDD) { + + if (puhLast) + puhLast->next = puh->next; + else + UserHookHead = puh->next; + + free(puh); + return TRUE; + } + puhLast = puh; + puh = puh->next; + } + + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; +} + +/*** VDDTerminateUserHook - This service is provided for VDDs to hook + * for callback services + * + * INPUT: + * USHORT DosPDB + * + * OUTPUT + * None + * + */ + +VOID VDDTerminateUserHook(USHORT DosPDB) +{ + + PVDD_USER_HANDLERS puh = UserHookHead; + + while(puh) { + if(puh->uterm_handler) + (puh->uterm_handler)(DosPDB); + puh = puh->next; + } + return; +} + +/*** VDDCreateUserHook - This service is provided for VDDs to hook + * for callback services + * + * INPUT: + * USHORT DosPDB + * + * OUTPUT + * None + * + */ + +VOID VDDCreateUserHook(USHORT DosPDB) +{ + + PVDD_USER_HANDLERS puh = UserHookHead; + + while(puh) { + if(puh->ucr_handler) + (puh->ucr_handler)(DosPDB); + puh = puh->next; + } + return; +} + +/*** VDDBlockUserHook - This service is provided for VDDs to hook + * for callback services + * + * INPUT: + * None + * + * OUTPUT + * None + * + */ + +VOID VDDBlockUserHook(VOID) +{ + + PVDD_USER_HANDLERS puh = UserHookHead; + + while(puh) { + if(puh->ublock_handler) + (puh->ublock_handler)(); + puh = puh->next; + } + return; +} + +/*** VDDResumeUserHook - This service is provided for VDDs to hook + * for callback services + * + * INPUT: + * None + * + * OUTPUT + * None + * + */ + +VOID VDDResumeUserHook(VOID) +{ + + PVDD_USER_HANDLERS puh = UserHookHead; + + while(puh) { + if(puh->uresume_handler) + (puh->uresume_handler)(); + puh = puh->next; + } + return; +} + +/*** VDDSimulate16 + * + * This service causes the simulation of intel instructions to start. + * + * INPUT + * None + * + * OUTPUT + * None + * + * NOTES + * This service is similar to VDDSimulateInterrupt except that + * it does'nt require a hardware interrupt to be supported by the + * 16bit stub device driver. This service allows VDD to execute + * a routine in its 16bit driver and come back when its done, kind + * of a far call. Before calling VDDSimulate16, VDD should preserve + * all the 16bit registers which its routine might destroy. Minimally + * it should at least preserve cs and ip. Then it should set the + * cs and ip for the 16bit routine. VDD could also use registers + * like ax,bx.. to pass parametrs to its 16bit routines. At the + * end of the 16bit routine VDDUnSimulate16 macro should be used + * which will send the control back to the VDD just after the + * call VDDSimulate16. Note very carefully that this simulation + * to 16bit is synchronous, i.e. VDD gets blocked in VDDSimulate16 + * and only comes back when stub-driver does a VDDUnSimulate16. + * Here is an example: + * + * vdd: + * SaveCS = getCS(); + * SaveIP = getIP(); + * SaveAX = getAX(); + * setCS (16BitRoutineCS); + * setIP (16BitRoutineIP); + * setAX (DO_X_OPERATION); + * VDDSimulate16 (); + * setCS (SavwCS); + * setIP (SaveIP); + * setAX (SaveAX); + * .. + * .. + * + * Stub Driver: (Initialization part) + * + * RegisterModule ; Loads VDD + * push cs + * pop ax + * mov bx, offset Simulate16 + * DispatchCall ; Passes the address of worker + * ; routine to VDD in ax:bx. + * + * Stub Driver (Run Time) + * + * Simulate16: + * .. + * .. ; do the operation index passed in ax + * + * VDDUnSimulate16 + * + */ + +VOID VDDSimulate16(VOID) +{ + cpu_simulate(); +} + +VOID HostTerminatePDB(USHORT PDB) +{ + FloppyTerminatePDB(PDB); + FdiskTerminatePDB(PDB); + +} diff --git a/private/mvdm/softpc.new/host/src/nt_munge.c b/private/mvdm/softpc.new/host/src/nt_munge.c new file mode 100644 index 000000000..5c48df4ee --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_munge.c @@ -0,0 +1,556 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Win32 mungeing routines. + * + * Description : This module contains the functions required to produce + * destination compatible pixel patterns from SoftPC video + * memory. + * + * Author : Jerry Sexton (based on X_munge.c) + * + * Notes : + * + */ + +#include <windows.h> +#include "insignia.h" +#include "host_def.h" + +#include "xt.h" +#include "gvi.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "egagraph.h" +#include <conapi.h> +#include "nt_graph.h" + +/*( +========================= ega_colour_hi_munge ============================= + +PURPOSE: Munge interleaved EGA plane data to bitmap form using lookup tables. +INPUT: (unsigned char *) plane0_ptr - ptr to plane0 data + (int) width - # of groups of 4 bytes on the line + (unsigned int *) dest_ptr - ptr to output buffer + (unsigned int *) lut0_ptr - munging luts + (int) height - # of scanlines to output (1 or 2) + (int) line_offset - distance to next scanline +OUTPUT: A nice bitmap in dest_ptr + +=========================================================================== +)*/ + +GLOBAL VOID +ega_colour_hi_munge(unsigned char *plane0_ptr, int width, + unsigned int *dest_ptr, unsigned int *lut0_ptr, + int height, int line_offset) +{ + unsigned int *lut1_ptr = lut0_ptr + LUT_OFFSET; + unsigned int *lut2_ptr = lut1_ptr + LUT_OFFSET; + unsigned int *lut3_ptr = lut2_ptr + LUT_OFFSET; + FAST unsigned int hi_res; + FAST unsigned int lo_res; + FAST unsigned int *l_ptr; + FAST half_word *data; + + /* make sure we get the line offset in ints not bytes */ + line_offset /= sizeof(int); + data = (half_word *) plane0_ptr; + + /* convert each input byte in turn */ + if (get_plane_mask() == 0xf) /* all planes enabled */ + { + for ( ; width > 0; width--) + { + /* Get 8 bytes (2 longs) of output data from 1 byte of plane 0 + ** data + */ + + l_ptr = &lut0_ptr [*data++ << 1]; + hi_res = *l_ptr++; + lo_res = *l_ptr; + + /* Or in the output data from plane 1 */ + l_ptr = &lut1_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Or in the output data from plane 2 */ + l_ptr = &lut2_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Or in the output data from plane 3 */ + l_ptr = &lut3_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Output the data to the buffer */ + if (height == 2) + { + /* scanline doubling */ + *(dest_ptr + line_offset) = hi_res; + *dest_ptr++ = hi_res; + *(dest_ptr + line_offset) = lo_res; + *dest_ptr++ = lo_res; + } + else + { + /* not scanline doubling */ + *dest_ptr++ = hi_res; + *dest_ptr++ = lo_res; + } + } + } + else + { + for ( ; width > 0; width--) + { + /* Get 8 bytes (2 longs) of output data from 1 byte of plane 0 + ** data + */ + + if (get_plane_mask() & 1) + { + l_ptr = &lut0_ptr [*data++ << 1]; + hi_res = *l_ptr++; + lo_res = *l_ptr; + } + else + { + hi_res = 0; + lo_res = 0; + data++; + } + + /* Conditionally Or in the output data from plane 1 */ + if (get_plane_mask() & 2) + { + l_ptr = &lut1_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Conditionally Or in the output data from plane 2 */ + if (get_plane_mask() & 4) + { + l_ptr = &lut2_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Conditionally Or in the output data from plane 3 */ + if (get_plane_mask() & 8) + { + l_ptr = &lut3_ptr [*data++ << 1]; + hi_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Output the data to the buffer */ + if (height == 2) + { + /* scanline doubling */ + *(dest_ptr + line_offset) = hi_res; + *dest_ptr++ = hi_res; + *(dest_ptr + line_offset) = lo_res; + *dest_ptr++ = lo_res; + } + else + { + /* not scanline doubling */ + *dest_ptr++ = hi_res; + *dest_ptr++ = lo_res; + } + } + } +} /* ega_colour_hi_munge */ + +#ifdef BIGWIN +/*( +========================= ega_colour_hi_munge_big =========================== + +PURPOSE: Munge interleaved EGA plane data to bitmap data for big windows. +INPUT: (unsigned char *) plane0_ptr - ptr to EGA plane 0 data + (int) width - number of bytes to convert + (unsigned int *) dest_ptr - output buffer ptr + (unsigned int *) lut0_ptr - ptr to luts + (int) height - # of scanlines to output (1 or 3) + (int) line_offset - distance to next scanline +OUTPUT: A nice bitmap in the output buffer + +============================================================================= +)*/ + +GLOBAL VOID +ega_colour_hi_munge_big(unsigned char *plane0_ptr, int width, + unsigned int *dest_ptr, unsigned int *lut0_ptr, + int height, int line_offset) +{ + unsigned int *lut1_ptr = lut0_ptr + BIG_LUT_OFFSET; + unsigned int *lut2_ptr = lut1_ptr + BIG_LUT_OFFSET; + unsigned int *lut3_ptr = lut2_ptr + BIG_LUT_OFFSET; + FAST unsigned int hi_res; + FAST unsigned int med_res; + FAST unsigned int lo_res; + FAST unsigned int *l_ptr; + FAST half_word *data; + + /* make sure we get the line offset in ints not bytes */ + line_offset /= sizeof(int); + data = (half_word *) plane0_ptr; + + if (get_plane_mask() == 0xf) + { + for ( ; width > 0; width--) + { + /* From one byte of input data in plane 0, get 12 bytes + ** of output data. + */ + + l_ptr = &lut0_ptr [*data++ * 3]; + hi_res = *l_ptr++; + med_res = *l_ptr++; + lo_res = *l_ptr; + + /* Or in the stuff from plane 1 */ + l_ptr = &lut1_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Or in the stuff from plane 2 */ + l_ptr = &lut2_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Or in the stuff from plane 3 */ + l_ptr = &lut3_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + + /* Output the munged data */ + if (height == 3) + { + /* triple the scanlines */ + *(dest_ptr + 2*line_offset) = hi_res; + *(dest_ptr + line_offset) = hi_res; + *dest_ptr++ = hi_res; + *(dest_ptr + 2*line_offset) = med_res; + *(dest_ptr + line_offset) = med_res; + *dest_ptr++ = med_res; + *(dest_ptr + 2*line_offset) = lo_res; + *(dest_ptr + line_offset) = lo_res; + *dest_ptr++ = lo_res; + } + else + { + /* just one scanline */ + *dest_ptr++ = hi_res; + *dest_ptr++ = med_res; + *dest_ptr++ = lo_res; + } + } + } + else + { + for ( ; width > 0; width--) + { + /* From one byte of input data in plane 0, get 12 bytes + ** of output data. + */ + + if (get_plane_mask() & 1) + { + l_ptr = &lut0_ptr [*data++ * 3]; + hi_res = *l_ptr++; + med_res = *l_ptr++; + lo_res = *l_ptr; + } + else + { + data++; + hi_res = 0; + med_res = 0; + lo_res = 0; + } + + /* Or in the stuff from plane 1 */ + if (get_plane_mask() & 2) + { + l_ptr = &lut1_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Or in the stuff from plane 2 */ + if (get_plane_mask() & 4) + { + l_ptr = &lut2_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Or in the stuff from plane 3 */ + if (get_plane_mask() & 8) + { + l_ptr = &lut3_ptr [*data++ * 3]; + hi_res |= *l_ptr++; + med_res |= *l_ptr++; + lo_res |= *l_ptr; + } + else + { + data++; + } + + /* Output the munged data */ + if (height == 3) + { + /* triple the scanlines */ + *(dest_ptr + 2*line_offset) = hi_res; + *(dest_ptr + line_offset) = hi_res; + *dest_ptr++ = hi_res; + *(dest_ptr + 2*line_offset) = med_res; + *(dest_ptr + line_offset) = med_res; + *dest_ptr++ = med_res; + *(dest_ptr + 2*line_offset) = lo_res; + *(dest_ptr + line_offset) = lo_res; + *dest_ptr++ = lo_res; + } + else + { + /* just one scanline */ + *dest_ptr++ = hi_res; + *dest_ptr++ = med_res; + *dest_ptr++ = lo_res; + } + } + } +} /* ega_colour_hi_munge_big */ + +/*( +========================= ega_colour_hi_munge_huge ======================== + +PURPOSE: Munge interleaved EGA plane data to bitmap form using lookup tables. +INPUT: (unsigned char *) plane0_ptr - ptr to plane0 data + (int) width - # of bytes on the line + (unsigned int *) dest_ptr - ptr to output buffer + (unsigned int *) lut0_ptr - munging luts + (int) height - # of scanlines to output (1 or 2) + (int) line_offset - distance to next scanline +OUTPUT: A nice X image in dest_ptr + +=========================================================================== +)*/ + +GLOBAL VOID +ega_colour_hi_munge_huge(unsigned char *plane0_ptr, int width, + unsigned int *dest_ptr, unsigned int *lut0_ptr, + int height, int line_offset) +{ + unsigned int *lut1_ptr = lut0_ptr + HUGE_LUT_OFFSET; + unsigned int *lut2_ptr = lut1_ptr + HUGE_LUT_OFFSET; + unsigned int *lut3_ptr = lut2_ptr + HUGE_LUT_OFFSET; + FAST unsigned int res4; + FAST unsigned int res3; + FAST unsigned int res2; + FAST unsigned int res1; + FAST unsigned int *l_ptr; + FAST half_word *data; + + /* make sure we get the line offset in ints not bytes */ + line_offset /= sizeof(int); + data = (half_word *) plane0_ptr; + + /* convert each input byte in turn */ + if (get_plane_mask() == 0xf) + { + for ( ; width > 0; width--) + { + /* Get 16 bytes of output data from 1 byte of plane 0 + ** data + */ + + l_ptr = &lut0_ptr [*data++ << 2]; + res4 = *l_ptr++; + res3 = *l_ptr++; + res2 = *l_ptr++; + res1 = *l_ptr; + + /* Or in the output data from plane 1 */ + l_ptr = &lut1_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + + /* Or in the output data from plane 2 */ + l_ptr = &lut2_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + + /* Or in the output data from plane 3 */ + l_ptr = &lut3_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + + /* Output the data to the buffer */ + if (height == 4) + { + /* scanline doubling */ + *(dest_ptr + 3*line_offset) = res4; + *(dest_ptr + 2*line_offset) = res4; + *(dest_ptr + line_offset) = res4; + *dest_ptr++ = res4; + *(dest_ptr + 3*line_offset) = res3; + *(dest_ptr + 2*line_offset) = res3; + *(dest_ptr + line_offset) = res3; + *dest_ptr++ = res3; + *(dest_ptr + 3*line_offset) = res2; + *(dest_ptr + 2*line_offset) = res2; + *(dest_ptr + line_offset) = res2; + *dest_ptr++ = res2; + *(dest_ptr + 3*line_offset) = res1; + *(dest_ptr + 2*line_offset) = res1; + *(dest_ptr + line_offset) = res1; + *dest_ptr++ = res1; + } + else + { + /* not scanline doubling */ + *dest_ptr++ = res4; + *dest_ptr++ = res3; + *dest_ptr++ = res2; + *dest_ptr++ = res1; + } + } + } + else + { + for ( ; width > 0; width--) + { + /* Get 16 bytes of output data from 1 byte of plane 0 + ** data + */ + + if (get_plane_mask() & 1) + { + l_ptr = &lut0_ptr [*data++ << 2]; + res4 = *l_ptr++; + res3 = *l_ptr++; + res2 = *l_ptr++; + res1 = *l_ptr; + } + else + { + res4 = 0; + res3 = 0; + res2 = 0; + res1 = 0; + data++; + } + + /* Or in the output data from plane 1 */ + if (get_plane_mask() & 2) + { + l_ptr = &lut1_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + } + else + { + data++; + } + + /* Or in the output data from plane 2 */ + if (get_plane_mask() & 4) + { + l_ptr = &lut2_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + } + else + { + data++; + } + + /* Or in the output data from plane 3 */ + if (get_plane_mask() & 8) + { + l_ptr = &lut3_ptr [*data++ << 2]; + res4 |= *l_ptr++; + res3 |= *l_ptr++; + res2 |= *l_ptr++; + res1 |= *l_ptr; + } + else + { + data++; + } + + /* Output the data to the buffer */ + if (height == 4) + { + /* scanline doubling */ + *(dest_ptr + 3*line_offset) = res4; + *(dest_ptr + 2*line_offset) = res4; + *(dest_ptr + line_offset) = res4; + *dest_ptr++ = res4; + *(dest_ptr + 3*line_offset) = res3; + *(dest_ptr + 2*line_offset) = res3; + *(dest_ptr + line_offset) = res3; + *dest_ptr++ = res3; + *(dest_ptr + 3*line_offset) = res2; + *(dest_ptr + 2*line_offset) = res2; + *(dest_ptr + line_offset) = res2; + *dest_ptr++ = res2; + *(dest_ptr + 3*line_offset) = res1; + *(dest_ptr + 2*line_offset) = res1; + *(dest_ptr + line_offset) = res1; + *dest_ptr++ = res1; + } + else + { + /* not scanline doubling */ + *dest_ptr++ = res4; + *dest_ptr++ = res3; + *dest_ptr++ = res2; + *dest_ptr++ = res1; + } + } + } +} /* ega_colour_hi_munge_huge */ +#endif /* BIGWIN */ diff --git a/private/mvdm/softpc.new/host/src/nt_nls.c b/private/mvdm/softpc.new/host/src/nt_nls.c new file mode 100644 index 000000000..eda6a1021 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_nls.c @@ -0,0 +1,128 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntstatus.h> +#include <windows.h> +#include "host_def.h" +#include "insignia.h" +/*[ + Name: nt_nls.c + Derived From: X_nls.c (Justin Koprowski) + Author: Jerry Sexton + Created On: 8th August 1991 + Purpose: + This modules contains strings that are required for the + .SoftPC file and the user interface. In addition it also + contains a routine, host_nls_get_msg, for retrieving strings + from the appropriate array, for ports that do not have native + language support. + +The following tables and routines are defined: + 1. config_message + 2. uis_message + 3. host_nls_get_msg + + (c)Copyright Insignia Solutions Ltd., 1990. All rights reserved. + +]*/ + +/* Global include files */ +#include <stdio.h> +#include <string.h> +#include "xt.h" +#include "error.h" +#include "host_rrr.h" +#include "host_nls.h" +#include "nt_uis.h" + +char szDoomMsg[MAX_PATH]=""; +char szSysErrMsg[MAX_PATH]=""; +#ifdef X86GFX +char szFrozenString[32]; +#endif +char szHideMouseMenuStr[64]; +char szDisplayMouseMenuStr[64]; + + + +/**************************************************************************** + Function: host_nls_get_message() + Purpose: Returns the required string from the + resource file. + Return Status: None. + Description: This routine is supplied with a message + number which falls in the following ranges: + 0-1000: base error messages + 1001-2000: host error message +******************************************************************************/ + +VOID +host_nls_get_msg( + int message_number, + CHAR *message_buffer, + int buf_len + ) +/* int message_number, Number of SoftPC message. + * buf_len; The maximum length of message, i.e. + * the size of message_buffer + * char *message_buffer; Pointer to a buffer into which the + * message is to be written + */ +{ + if (!LoadString(GetModuleHandle(NULL), + message_number, + message_buffer, + buf_len)) + { + strncpy(message_buffer, szDoomMsg, buf_len); + message_buffer[buf_len-1] = '\0'; + } +} + +void nls_init(void) +{ + + if (!LoadString(GetModuleHandle(NULL), + EHS_SYSTEM_ERROR, + szSysErrMsg, + sizeof(szSysErrMsg)/sizeof(CHAR) + ) + || + !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + ERROR_NOT_ENOUGH_MEMORY, + 0, + szDoomMsg, + sizeof(szDoomMsg)/sizeof(CHAR), + NULL + ) +#ifdef X86GFX + || + !LoadString(GetModuleHandle(NULL), + IDS_BURRRR, + szFrozenString, + sizeof(szFrozenString)/sizeof(CHAR) + ) +#endif + || + !LoadString(GetModuleHandle(NULL), + SM_HIDE_MOUSE, + szHideMouseMenuStr, + sizeof(szHideMouseMenuStr)/sizeof(char) + ) + || + !LoadString(GetModuleHandle(NULL), + SM_DISPLAY_MOUSE, + szDisplayMouseMenuStr, + sizeof(szDisplayMouseMenuStr)/sizeof(char) + )) + { + RaiseException((DWORD)STATUS_INSUFFICIENT_RESOURCES, + EXCEPTION_NONCONTINUABLE, + 0, + NULL + ); + } + + return; +} diff --git a/private/mvdm/softpc.new/host/src/nt_ntfun.c b/private/mvdm/softpc.new/host/src/nt_ntfun.c new file mode 100644 index 000000000..8d98c959d --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_ntfun.c @@ -0,0 +1,592 @@ +#include <nt.h> +#include <ntrtl.h> +#include <ntddser.h> +#include <nturtl.h> +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> + +#include "insignia.h" +#include "trace.h" +#include "host_trc.h" +#include "debug.h" +#include "nt_com.h" +#include "nt_reset.h" + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Defines */ + +#define SETUPLASTERROR(NtStatus) SetLastError(RtlNtStatusToDosError(NtStatus)) + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::: Magic xoff ioctl and associated functions ::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +typedef struct IoStatusElement +{ + struct IoStatusElement *NxtStatusBlock; //Ptr to next status block + IO_STATUS_BLOCK ioStatusBlock; +} IOSTATUSLIST, *PIOSTATUSLIST ; + + +int SendXOFFIoctl( + +HANDLE FileHandle, // Handle of comms port to send xoff ioctl to +HANDLE Event, // Event to signal completion of ioctl on +int Timeout, // Ioctl timeout +int Count, // Ioctl RX character count value +int XoffChar, // XOFF character +void *StatusElem) // Ptr to IO status block element +{ + int exitcode; + NTSTATUS rtn; // Return code from IOCTL + SERIAL_XOFF_COUNTER ioctl; // XOFF IOCTL + + /*................................................... Setup XOFF ioctl */ + + ioctl.Timeout = Timeout; // IOCTL timeout in milliseconds + ioctl.Counter = (LONG) Count; // RX count + ioctl.XoffChar = (UCHAR) XoffChar; // XOFF character + + /*............................................. issue magic xoff ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, + &(((PIOSTATUSLIST) StatusElem)->ioStatusBlock), + IOCTL_SERIAL_XOFF_COUNTER, + (PVOID) &ioctl, sizeof(ioctl), NULL, 0))) + { + // Should display an error here + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); + exitcode = FALSE; + } + else + exitcode = TRUE; + + return(exitcode); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::: Allocate IO status element */ + +void *AllocStatusElement() +{ + void *new; + + /*:::::::::::::::::::::::::::::: Allocate space for new io status block */ + + if((new = calloc(1,sizeof(IOSTATUSLIST))) == NULL) + { + // Allocation error do something about it + ; + } + else + ((PIOSTATUSLIST) new)->ioStatusBlock.Status = -1; + + return(new); +} + +/*:::::::::::::::::::::::::::::::::::: Add new iostatusblock to linked list */ + +void *AddNewIOStatusBlockToList(void **firstBlock, void **lastBlock, void *new) +{ + + /*:::::::::::::::::::::::::::::::::::::::: Add new block to linked list */ + + if(*lastBlock) + ((PIOSTATUSLIST)*lastBlock)->NxtStatusBlock = (PIOSTATUSLIST) new; + + /*:::::::::::::::::: Update first and last linked list element pointers */ + + if(!*firstBlock) *firstBlock = new; // First item in list + + *lastBlock = new; // Update last item pointer + + return((void *) new); +} + +/*:::::::::::::::::::::::::: Remove completed XOFF ioctl's from linked list */ + +int RemoveCompletedIOCTLs(void **firstBlock, void **lastBlock) +{ + PIOSTATUSLIST remove, nxt = (PIOSTATUSLIST) *firstBlock; + + /*::::::::::::::::::::::::: Scan linked list removing completed ioctl's */ + + while(nxt && nxt->ioStatusBlock.Status != -1) + { + /*......................... IOCTL completed, remove io status block */ + + remove = nxt; // Element to remove + nxt = nxt->NxtStatusBlock; // Next element to process + +#ifndef PROD + switch(remove->ioStatusBlock.Status) + { + case STATUS_SUCCESS: + sub_note_trace0(HOST_COM_VERBOSE,"XOFF (counter)\n"); + break; + + case STATUS_SERIAL_MORE_WRITES: + sub_note_trace0(HOST_COM_VERBOSE,"XOFF (more writes)\n"); + break; + + case STATUS_SERIAL_COUNTER_TIMEOUT: + sub_note_trace0(HOST_COM_VERBOSE,"XOFF (timeout)\n"); + break; + + default: + sub_note_trace0(HOST_COM_VERBOSE,"XOFF (unknown)\n"); + break; + } +#endif + + free(remove); // Deallocate element + } + + /*::::::::::::::::::::::::::::::: Update first and last element pointers */ + + if(!nxt) + { + // List empty reset first/last pointers + *firstBlock = *lastBlock = NULL; + } + else + { + // Setup new first pointer + *firstBlock = (void *) nxt; + } + + + // Returns true if there are still outstanding XOFF ioctl's + return(nxt ? TRUE : FALSE); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +int FastSetUpComms( + +HANDLE FileHandle, // Handle of comms port to send xoff ioctl to +HANDLE Event, // Event to signal completion of ioctl on +int InputQueueSize, +int OutputQueueSize) +{ + NTSTATUS rtn; + SERIAL_QUEUE_SIZE ioctl; + IO_STATUS_BLOCK ioStatusBlock; + + /*........................................................ Setup ioctl */ + + ioctl.InSize = InputQueueSize; + ioctl.OutSize = OutputQueueSize; + + /*............................................. issue magic xoff ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, + &ioStatusBlock, + IOCTL_SERIAL_SET_QUEUE_SIZE, + (PVOID) &ioctl, sizeof(ioctl), NULL, 0))) + { + // Should display an error here +#ifndef PROD + fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); +#endif + return(FALSE); + } + + /*......................................... Wait for IOCTL to complete */ + + if(rtn == STATUS_PENDING) + NtWaitForSingleObject(Event, FALSE, NULL); + + /*............................................ Check completion status */ + +#ifndef PROD + if(ioStatusBlock.Status != STATUS_SUCCESS) + fprintf(trace_file, "FastSetupComm failed (%x)\n",ioStatusBlock.Status); +#endif + + return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::: Fast track SetCommMask call ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int FastSetCommMask( + +HANDLE FileHandle, // Handle of comms port to send ioctl to +HANDLE Event, // Event to signal completion of ioctl on +ULONG CommMask) +{ + NTSTATUS rtn; + IO_STATUS_BLOCK ioStatusBlock; + + /*.......................................... issue set comm mask ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, + &ioStatusBlock, + IOCTL_SERIAL_SET_WAIT_MASK, + (PVOID) &CommMask, sizeof(CommMask), NULL, 0))) + { + // Should display an error here +#ifndef PROD + fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); +#endif + return(FALSE); + } + + /*......................................... Wait for IOCTL to complete */ + + if(rtn == STATUS_PENDING) + NtWaitForSingleObject(Event, FALSE, NULL); + + /*............................................ Check completion status */ + +#ifndef PROD + if(ioStatusBlock.Status != STATUS_SUCCESS) + fprintf(trace_file,"FastSetCommMask failed (%x)\n",ioStatusBlock.Status); +#endif + + return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Fast track GetCommModemStatus call ::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int FastGetCommModemStatus( + +HANDLE FileHandle, // Handle of comms port to send ioctl to +HANDLE Event, // Event to signal completion of ioctl on +PULONG ModemStatus) +{ + NTSTATUS rtn; + IO_STATUS_BLOCK ioStatusBlock; + + /*.......................................... issue set comm mask ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, + &ioStatusBlock, + IOCTL_SERIAL_GET_MODEMSTATUS, + NULL, 0, + (PVOID) ModemStatus, sizeof(ModemStatus)))) + { + // Should display an error here +#ifndef PROD + fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); +#endif + return(FALSE); + } + + /*......................................... Wait for IOCTL to complete */ + + if(rtn == STATUS_PENDING) + NtWaitForSingleObject(Event, FALSE, NULL); + + /*............................................ Check completion status */ + +#ifndef PROD + if(ioStatusBlock.Status != STATUS_SUCCESS) + fprintf(trace_file,"GetCommModemStatus failed (%x)\n",ioStatusBlock.Status); +#endif + + return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Wait for a wakeup call from the CPU thread or serial driver :::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +//WARNING : This function can only be called from one thread within a process + + +BOOL FastWaitCommsOrCpuEvent( +HANDLE FileHandle, //File handle or communications port +PHANDLE CommsCPUWaitEvents, //Table or CPU thread and comms wait events +int CommsEventInx, //Index in above table to comms event +PULONG EvtMask, //Return Comms completion mask there +PULONG SignalledObj) +{ + NTSTATUS rtn; + static IO_STATUS_BLOCK ioStatusBlock; + static BOOL WaitCommEventOutStanding = FALSE; + + /*................................................ Is this a init call */ + + if(FileHandle == NULL) + { + WaitCommEventOutStanding = FALSE; + return(TRUE); //Init successful + } + + /*......................... Do we need to issue a new WaitComm ioctl ? */ + + if(!WaitCommEventOutStanding) + { + + /*...................................... Issue WaitCommEvent ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, + CommsCPUWaitEvents[CommsEventInx], + NULL, + NULL, + &ioStatusBlock, + IOCTL_SERIAL_WAIT_ON_MASK, + NULL, + 0, + EvtMask, + sizeof(ULONG))) ) + { + // Should display an error here +#ifndef PROD + fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); +#endif + SETUPLASTERROR(rtn); + return(FALSE); + } + else + WaitCommEventOutStanding = TRUE; + } + else + rtn = STATUS_PENDING; // Already pending WaitCommEvent ioctl + + /*.......................... Wait for communication or CPU thread event */ + + if(rtn == STATUS_PENDING) + { + *SignalledObj = NtWaitForMultipleObjects(2, + CommsCPUWaitEvents, + WaitAny, + FALSE, + NULL + ); + + /*........... Did wait complete because of a communications event ? */ + + if(*SignalledObj == (ULONG)CommsEventInx) + { + // Get result from WaitCommEvent ioctl + + WaitCommEventOutStanding = FALSE; + if(ioStatusBlock.Status != STATUS_SUCCESS) + { + SETUPLASTERROR(ioStatusBlock.Status); + return(FALSE); + } + } + } + else + { + //WaitCommEvent completed instantly + *SignalledObj = CommsEventInx; + WaitCommEventOutStanding = FALSE; + } + + return(TRUE); +} + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::: Turn on MSR,LSR, RX streaming mode :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +BOOL EnableMSRLSRRXmode( + +HANDLE FileHandle, // Handle of comms port to send ioctl to +HANDLE Event, // Event to signal completion of ioctl on +unsigned char EscapeChar) +{ + NTSTATUS rtn; + IO_STATUS_BLOCK ioStatusBlock; + + /*........................................................ issue ioctl */ + + if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, + &ioStatusBlock, + IOCTL_SERIAL_LSRMST_INSERT, + &EscapeChar, sizeof(unsigned char),NULL,0))) + { +#ifndef PROD + fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); + fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); +#endif + return(FALSE); + } + + /*......................................... Wait for IOCTL to complete */ + + if (rtn == STATUS_PENDING) + NtWaitForSingleObject(Event, FALSE, NULL); + + + /*............................................ Check completion status */ + +#ifndef PROD + if(ioStatusBlock.Status != STATUS_SUCCESS) + fprintf(trace_file,"IOCTL_SERIAL_LSRMST_INSERT ioctl failed (%x)\n", + ioStatusBlock.Status); +#endif + + return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); +} + + +/* Function to set a new baudrate for the comm device. + * Input: FileHandle -- file handle to the comm device + * BaudRate -- new baudrate to be set for the comm device + * output: TRUE if the function succeed + * FALSE if the function failed +**/ + + +BOOL FastCommSetBaudRate(HANDLE FileHandle, int BaudRate) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE SyncEvent; + SERIAL_BAUD_RATE LocalBaud; + + SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (SyncEvent == NULL) + return FALSE; + + LocalBaud.BaudRate = (ULONG)BaudRate; + + Status = NtDeviceIoControlFile(FileHandle, + SyncEvent, + NULL, + NULL, + &IoStatusBlock, + IOCTL_SERIAL_SET_BAUD_RATE, + &LocalBaud, + sizeof(LocalBaud), + NULL, + 0 + ); + if (Status == STATUS_PENDING) + NtWaitForSingleObject(SyncEvent, FALSE, NULL); + CloseHandle(SyncEvent); + return(NT_SUCCESS(IoStatusBlock.Status)); +} + +/* Function to set the new line control to the given comm device + * Input: FileHanlde -- file handle to the comm device + * StopBits -- new Stopbits + * Parity -- new parity + * DataBits -- new databits + * Output: + * TRUE if the function succeed. + * FALSE if the function failed. +**/ +BOOL FastCommSetLineControl(HANDLE FileHandle, UCHAR StopBits, UCHAR Parity, + UCHAR DataBits) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE SyncEvent; + SERIAL_LINE_CONTROL LocalLC; + + + /* make sure Windows and NT has the same definiation because + * the caller only deal with WINDOWS value while we will be returning + * NT values(NO_PARITY, STOP_BIT_1 and etc). + */ + ASSERT(NOPARITY == NO_PARITY && ODDPARITY == ODD_PARITY && + EVENPARITY == EVEN_PARITY && MARKPARITY == MARK_PARITY && + SPACEPARITY == SPACE_PARITY); + ASSERT(ONESTOPBIT == STOP_BIT_1 && ONE5STOPBITS == STOP_BITS_1_5 && + TWOSTOPBITS == STOP_BITS_2); + + /* Create an event to wait for the NT call */ + SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (SyncEvent == NULL) + return FALSE; + + LocalLC.StopBits = StopBits; + LocalLC.Parity = Parity; + LocalLC.WordLength = DataBits; + + Status = NtDeviceIoControlFile(FileHandle, + SyncEvent, + NULL, + NULL, + &IoStatusBlock, + IOCTL_SERIAL_SET_LINE_CONTROL, + &LocalLC, + sizeof(LocalLC), + NULL, + 0 + ); + if (Status == STATUS_PENDING) + NtWaitForSingleObject(SyncEvent, FALSE, NULL); + + CloseHandle(SyncEvent); + return(NT_SUCCESS(IoStatusBlock.Status)); +} + +/* Function to retrieve the given comm device current line control setting + * Input: FileHandle -- file handle to the comm device + * StopBits, Parity and DataBits are pointers to the placeholders + * to receive Stop bits, Parity and Data bits repectively. + * Output: + * TRUE if the function succeed + * FALSE if the function failed. +**/ + +BOOL FastCommGetLineControl(HANDLE FileHandle, UCHAR *StopBits, UCHAR *Parity, + UCHAR *DataBits) +{ + NTSTATUS Status; + SERIAL_LINE_CONTROL LocalLC; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE SyncEvent; + + /* make sure Windows and NT has the same definiation because + * the parameters we received from the caller are WINDOWS value + * while we will be calling NT API using NT values + */ + ASSERT(NOPARITY == NO_PARITY && ODDPARITY == ODD_PARITY && + EVENPARITY == EVEN_PARITY && MARKPARITY == MARK_PARITY && + SPACEPARITY == SPACE_PARITY); + ASSERT(ONESTOPBIT == STOP_BIT_1 && ONE5STOPBITS == STOP_BITS_1_5 && + TWOSTOPBITS == STOP_BITS_2); + + ASSERT(StopBits != NULL && Parity != NULL && DataBits != NULL); + + SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (SyncEvent == NULL) + return FALSE; + Status = NtDeviceIoControlFile(FileHandle, + SyncEvent, + NULL, + NULL, + &IoStatusBlock, + IOCTL_SERIAL_GET_LINE_CONTROL, + NULL, + 0, + &LocalLC, + sizeof(LocalLC) + ); + if (Status == STATUS_PENDING) + NtWaitForSingleObject(SyncEvent, FALSE, NULL); + + CloseHandle(SyncEvent); + + if (NT_SUCCESS(IoStatusBlock.Status)) { + *StopBits = LocalLC.StopBits; + *Parity = LocalLC.Parity; + *DataBits = LocalLC.WordLength; + return TRUE; + } + return FALSE; +} diff --git a/private/mvdm/softpc.new/host/src/nt_pif.c b/private/mvdm/softpc.new/host/src/nt_pif.c new file mode 100644 index 000000000..84371ef2f --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_pif.c @@ -0,0 +1,442 @@ +/*================================================================ + +nt_pif.c + +Code to read the relevant data fields from a Windows Program +Information File for use with the SoftPC / NT configuration +system. + +Andrew Watson 31/1/92 +This line causes this file to be build with a checkin of NT_PIF.H + +================================================================*/ + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "insignia.h" +#include "host_def.h" + +#include <pif.h> +#include "nt_pif.h" +#include "nt_reset.h" +#include <oemuni.h> +#include "error.h" + + + // + // holds config.sys and autoexec name from pif file + // if none specifed, then NULL. + // +static char *pchConfigFile=NULL; +static char *pchAutoexecFile=NULL; +VOID GetPIFConfigFiles(BOOL bConfig, char *pchFileName); + +DWORD dwWNTPifFlags; +UCHAR WNTPifFgPr = 100; +UCHAR WNTPifBgPr = 100; + +char achSlash[] ="\\"; +char achConfigNT[] ="config.nt"; +char achAutoexecNT[]="autoexec.nt"; + + +/* GetPIFConfigFile + * + * Copies PIF file specified name of config.sys\autoexec.bat + * to be used if none specified then uses + * "WindowsDir\config.nt" or "WindowsDir\autoexec.nt" + * + * ENTRY: BOOLEAN bConfig - TRUE retrieve config.sys + * FALSE retrieve autoexec.bat + * + * char *pchFile - destination for path\file name + * + * The input buffer must be at least MAX_PATH + 8.3 BaseName in len + * + * This routine cannot fail, but it may return a bad file name! + */ +VOID GetPIFConfigFiles(BOOL bConfig, char *pchFileName) +{ + DWORD dw; + char **ppch; + + + ppch = bConfig ? &pchConfigFile : &pchAutoexecFile; + if (!*ppch) + { + dw = GetSystemDirectory(pchFileName, MAX_PATH); + if (!dw || *(pchFileName+dw-1) != achSlash[0]) + strcat(pchFileName, achSlash); + strcat(pchFileName, bConfig ? achConfigNT : achAutoexecNT); + } + else { + dw = ExpandEnvironmentStringsOem(*ppch, pchFileName, MAX_PATH+12); + if (!dw || dw > MAX_PATH+12) { + *pchFileName = '\0'; + } + free(*ppch); + *ppch = NULL; + } +} + + +void SetPifDefaults(PIF_DATA *); + +/*=============================================================== + +Function: GetPIFData() + +Purpose: This function gets the PIF data from the PIF file + associated with the executable that SoftPC is trying + to run. + +Input: FullyQualified PifFileName, + if none supplied _default.pif will be used + +Output: A structure containing data that config needs. + +Returns: TRUE if the data has been gleaned successfully, FALSE + if not. + +================================================================*/ + +BOOL GetPIFData(PIF_DATA * pd, char *PifName) +{ + DWORD dw; + CHAR achDef[]="\\_default.pif"; + PIFEXTHDR exthdr; + STDPIF pif286; + W386PIF30 ext386; + W286PIF30 ext286; + WNTPIF31 extWNT; + WENHPIF40 extWin95; + HFILE filehandle; + char pathBuff[MAX_PATH*2]; + BOOL bGot386, bGotWin95; + int index; + char *CmdLine; + WORD IdleSensitivity; + + CmdLine = NULL; + dwWNTPifFlags = 0; + + // + // set the defaults in case of error or in case we can't find + // all of the pif settings information now for easy error exit + // + SetPifDefaults(pd); + + // if no PifName, use %windir%\_default.pif + if (!*PifName) { + dw = GetWindowsDirectory(pathBuff, sizeof(pathBuff) - sizeof(achDef)); + if (!dw || dw > sizeof(pathBuff) - sizeof(achDef)) { + return FALSE; // give it up... use default settings + } + strcat(pathBuff, achDef); + PifName = pathBuff; + } + + +/*================================================================ +Open the file whose name was passed as a parameter to GetPIFData() +and if an invalid handle to the file is returned (-1), then quit. +The file specified is opened for reading only. +================================================================*/ + +if((filehandle=_lopen(PifName,OF_READ)) == (HFILE) -1) + { + /* must be an invalid handle ! */ + return FALSE; + } + + +/*================================================================ +Get the main block of data from the PIF file. +================================================================*/ + +/* Read in the main block of file data into the structure */ +if(_llseek(filehandle,0,0) == -1) + { + _lclose(filehandle); + return FALSE; + } +if(_lread(filehandle,(LPSTR)&pif286,sizeof(pif286)) == -1) + { + _lclose(filehandle); + return FALSE; + } + +/*============================================================== +Go to the PIF extension signature area and try to read the +header in. +==============================================================*/ + +if (_lread(filehandle,(LPSTR)&exthdr,sizeof(exthdr)) == -1) + { + _lclose(filehandle); + return FALSE; + } + + // do we have any extended headers ? +if (!strcmp(exthdr.extsig, STDHDRSIG)) + { + bGot386 = FALSE; + bGotWin95 = FALSE; + while (exthdr.extnxthdrfloff != LASTHEADER) + { + // + // move to next extended header and read it in + // + if (_llseek(filehandle,exthdr.extnxthdrfloff,0) == -1) + { + _lclose(filehandle); + return FALSE; + } + if (_lread(filehandle,(LPSTR)&exthdr,sizeof(exthdr)) == -1) + { + _lclose(filehandle); + return FALSE; + } + + // + // Get 286 extensions, note that 386 extensions take precedence + // + if (!strcmp(exthdr.extsig, W286HDRSIG) && !bGot386) + { + if(_llseek(filehandle, exthdr.extfileoffset, 0) == -1 || + _lread(filehandle,(LPSTR)&ext286,sizeof(ext286)) == -1) + { + _lclose(filehandle); + return FALSE; + } + pd->xmsdes =ext286.PfMaxXmsK; + pd->xmsreq =ext286.PfMinXmsK; + pd->reskey =ext286.PfW286Flags & 3; + pd->reskey |= (ext286.PfW286Flags << 2) & 0x70; + } + // + // Get 386 extensions + // + else if (!strcmp(exthdr.extsig, W386HDRSIG30)) + { + if(_llseek(filehandle, exthdr.extfileoffset, 0) == -1 || + _lread(filehandle,(LPSTR)&ext386,sizeof(ext386)) == -1) + { + _lclose(filehandle); + return FALSE; + } + bGot386 = TRUE; + pd->emsdes=ext386.PfMaxEMMK; + pd->emsreq=ext386.PfMinEMMK; + pd->xmsdes=ext386.PfMaxXmsK; + pd->xmsreq=ext386.PfMinXmsK; + if (!bGotWin95 && ext386.PfFPriority < 100) { + WNTPifFgPr = (UCHAR)ext386.PfFPriority; // Foreground priority + } + if (!bGotWin95 && ext386.PfBPriority < 50) { + WNTPifBgPr = (UCHAR)ext386.PfBPriority; // Background priority + WNTPifBgPr <<= 1; // set def 50 to 100 + } + pd->reskey = (char)((ext386.PfW386Flags >> 5) & 0x7f); // bits 5 - 11 are reskeys + pd->menuclose = (char)(ext386.PfW386Flags & 1); // bottom bit sensitive + pd->ShortScan = ext386.PfHotKeyScan; // scan code of shortcut key + pd->ShortMod = ext386.PfHotKeyShVal; // modifier code of shortcut key + if (!bGotWin95) + pd->idledetect = (char)((ext386.PfW386Flags >> 12) & 1); + pd->fullorwin = (WORD)((ext386.PfW386Flags & fFullScreen) >> 3); + bPifFastPaste = (ext386.PfW386Flags & fINT16Paste) != 0; + CmdLine = ext386.PfW386params; + } + // + // Get Windows Nt extensions + // + else if (!strcmp(exthdr.extsig, WNTEXTSIG)) + { + if(_llseek(filehandle, exthdr.extfileoffset, 0) == -1 || + _lread(filehandle,(LPSTR)&extWNT, sizeof(extWNT)) == -1) + { + _lclose(filehandle); + return FALSE; + } + + dwWNTPifFlags = extWNT.nt31Prop.dwWNTFlags; + pd->SubSysId = (char) (dwWNTPifFlags & NTPIF_SUBSYSMASK); + + /* take autoexec.nt and config.nt from .pif file + only if we are running on a new console or it is from + forcedos/wow + */ + if (!pd->IgnoreConfigAutoexec) + { + pchConfigFile = ch_malloc(PIFDEFPATHSIZE); + extWNT.nt31Prop.achConfigFile[PIFDEFPATHSIZE-1] = '\0'; + if (pchConfigFile) { + strcpy(pchConfigFile, extWNT.nt31Prop.achConfigFile); + } + + pchAutoexecFile = ch_malloc(PIFDEFPATHSIZE); + extWNT.nt31Prop.achAutoexecFile[PIFDEFPATHSIZE-1] = '\0'; + if (pchAutoexecFile) { + strcpy(pchAutoexecFile, extWNT.nt31Prop.achAutoexecFile); + } + } + + } + // + // Get Win95 extenstion + // + else if (!strcmp(exthdr.extsig, WENHHDRSIG40)) + { + bGotWin95 = TRUE; + if(_llseek(filehandle, exthdr.extfileoffset, 0) == -1 || + _lread(filehandle,(LPSTR)&extWin95, sizeof(extWin95)) == -1) + { + _lclose(filehandle); + return FALSE; + } + IdleSensitivity = extWin95.tskProp.wIdleSensitivity; + if (IdleSensitivity < 10) { + // disable idle detection completely + pd->idledetect = 0; + } + else if (IdleSensitivity > 50 && IdleSensitivity <= 100) { + // + // 10 <= priority <= 100 (yeild rate = 90% ~ 0%) + // + WNTPifFgPr = + WNTPifBgPr = 10 + (100 - IdleSensitivity) * 9 / 5; + } + else { + WNTPifFgPr = + WNTPifBgPr = 100; + } + // TSK_BACKGROUND means "do not suspend the application + // when it is running in background" + if (!(extWin95.tskProp.flTsk & TSK_BACKGROUND)) { + WNTPifBgPr = 10; + } + + } + } // while !lastheader + + /* pif file handling strategies on NT: + (1). application was launched from a new created console + Take everything from the pif file. + + (2). application was launched from an existing console + if (ForceDos pif file) + take everything + else + only take softpc stuff and ignore every name strings in the + pif file such as + * wintitle + * startup directory + * optional parameters + * startup file + * autoexec.nt + * config.nt and + + some softpc setting: + + * close on exit. + * full screen and windowed mode + + Every name strings in a pif file is in OEM character set. + + */ + + if (DosSessionId || + (pfdata.AppHasPIFFile && pd->SubSysId == SUBSYS_DOS)) + { + if (pif286.appname[0] && !pd->IgnoreTitleInPIF) { + /* grab wintitle from the pif file. Note that the title + in the pif file is not a NULL terminated string. It always + starts from a non-white character then the real + title(can have white characters between words) and finally + append with SPACE characters. The total length is 30 characters. + */ + for (index = 29; index >= 0; index-- ) + if (pif286.appname[index] != ' ') + break; + if (index >= 0 && (pd->WinTitle = ch_malloc(MAX_PATH + 1))) { + RtlMoveMemory(pd->WinTitle, pif286.appname, index + 1); + pd->WinTitle[index + 1] = '\0'; + } + } + if (pif286.defpath[0] && !pd->IgnoreStartDirInPIF && + (pd->StartDir = ch_malloc(MAX_PATH + 1))) + strcpy(pd->StartDir, pif286.defpath); + + if (!pd->IgnoreCmdLineInPIF) { + CmdLine = (CmdLine) ? CmdLine : pif286.params; + if (CmdLine && *CmdLine && (pd->CmdLine = ch_malloc(MAX_PATH + 1))) + strcpy(pd->CmdLine, CmdLine); + } + if (DosSessionId) + pd->CloseOnExit = (pif286.MSflags & 0x10) ? 1 : 0; + + /* if the app has a pif file, grab the program name. + This can be discarded if it turns out the application itself + is not a pif file. + */ + if (pd->AppHasPIFFile) { + pd->StartFile = ch_malloc(MAX_PATH + 1); + if (pd->StartFile) + strcpy(pd->StartFile, pif286.startfile); + } + } + } + +_lclose(filehandle); +return TRUE; + +} + + + +/*=============================================================== +Function to set up the default options for memory state. +The default options are defined in nt_pif.h +===============================================================*/ + +void SetPifDefaults(PIF_DATA *pd) +{ + pd->memreq = DEFAULTMEMREQ; + pd->memdes = DEFAULTMEMDES; + pd->emsreq = DEFAULTEMSREQ; + pd->emsdes = DEFAULTEMSLMT; + pd->xmsreq = DEFAULTXMSREQ; + pd->xmsdes = DEFAULTXMSLMT; + pd->graphicsortext = DEFAULTVIDMEM; + pd->fullorwin = DEFAULTDISPUS; + pd->menuclose = 1; + pd->idledetect = 1; + pd->ShortMod = 0; // No shortcut keys + pd->ShortScan = 0; + pd->reskey = 0; // No reserve keys + pd->CloseOnExit = 1; + pd->WinTitle = NULL; + pd->CmdLine = NULL; + pd->StartFile = NULL; + pd->StartDir = NULL; + pd->SubSysId = SUBSYS_DEFAULT; +} + +/* + * Allocate NumBytes memory and exit cleanly on failure. + */ +void *ch_malloc(unsigned int NumBytes) +{ + + unsigned char *p = NULL; + + while ((p = malloc(NumBytes)) == NULL) { + if(RcMessageBox(EG_MALLOC_FAILURE, "", "", + RMB_ABORT | RMB_RETRY | RMB_IGNORE | + RMB_ICON_STOP) == RMB_IGNORE) + break; + } + return(p); +} diff --git a/private/mvdm/softpc.new/host/src/nt_reset.c b/private/mvdm/softpc.new/host/src/nt_reset.c new file mode 100644 index 000000000..8b004fe9e --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_reset.c @@ -0,0 +1,422 @@ +/* + * SoftPC Revision 3.0 + * + * Title : NT reset functions + * + * Description : This function is called by the standard reset function to + * set up any specific devices used by the Sun4 implementation. + * + * Author : SoftPC team + * + * Notes : + */ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdm.h> +#include <vdmapi.h> +#include "insignia.h" +#include "host_def.h" + +#ifdef X86GFX +#include <ntddvdeo.h> +#endif + +#include <sys\types.h> +#include "xt.h" +#include "sas.h" +#include "bios.h" +#include "keyboard.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "gvi.h" +#include "mouse_io.h" +#include "error.h" +#include "config.h" +#include "host.h" +#include "timer.h" +#include "idetect.h" +#include CpuH +#include "debug.h" +#include <stdio.h> +#include <stdlib.h> +#include <conapi.h> +#include "nt_timer.h" +#include "nt_graph.h" +#include "ntcheese.h" +#include "nt_uis.h" +#include "nt_com.h" +#include "nt_reset.h" +#include "nt_event.h" +#include "nt_fulsc.h" +#include "nt_eoi.h" +#include "video.h" +#include "nt_thred.h" + + +VOID DeleteConfigFiles(VOID); // from command.lib +void ShowStartGlass (DWORD); // private user api + +extern VIDEOFUNCS nt_video_funcs; +extern KEYBDFUNCS nt_keybd_funcs; +extern HOSTMOUSEFUNCS the_mouse_funcs; + +#ifndef MONITOR +extern WORD BWVKey; +extern char achES[]; +#endif + +#ifdef MONITOR +extern VOID AddTempIVTFixups(VOID); +#endif + +extern IU8 lcifo[]; + +/* + * Exported Data + */ +GLOBAL BOOL VDMForWOW = FALSE; +GLOBAL BOOL fSeparateWow = FALSE; // TRUE if CREATE_SEPARATE_WOW_VDM flag +GLOBAL HANDLE MainThread; +GLOBAL ULONG DosSessionId = 0; +GLOBAL UINT VdmExitCode = 0xFF; +GLOBAL BOOL StreamIoSwitchOn = TRUE; + +/* + * + * ============================================================================ + * External functions + * =========================================================================== + * = + */ + +void +host_reset() +{ + +#ifdef X86GFX + InitDetect(); +#endif + + if (host_stream_io_enabled) { + sc.ScreenState = STREAM_IO; + ConsoleInitialised = TRUE; + } + else { + + ConsoleInit(); + MouseAttachMenuItem(sc.ActiveOutputBufferHandle); + /*::::::::::::::::::::::::::::::::::::::::::::::::: Enable idle detect */ + } + +#ifdef MONITOR + /* Borrow the end of this routine to add temp code that hooks certain + * Ints back to the VDM and not into the native BIOS. These will only + * be active for the DOSEM initialisation ie until keyboard.sys can + * come along and do it properly. We must do this though as some real + * BIOS' can hang on certain initialisation functions. eg Dec 486/50 + * will hang on printer init as it is waiting for a responce from a + * 'private' port. + */ + AddTempIVTFixups(); +#endif /* MONITOR */ + + + // + // Let the heartbeat thread run and release the ica lock, + // on x86 needed now, for fullscreen switch notification. + // + ResumeThread(ThreadInfo.HeartBeat.Handle); + +#ifdef MONITOR + WaitIcaLockFullyInitialized(); +#endif + + host_ica_unlock(); + +#ifdef HUNTER + IDLE_ctl(FALSE); /* makes Trapper too slow */ +#else /* ! ( HUNTER ) */ + if (sc.ScreenState == FULLSCREEN) // initialised in ConsoleInit() + IDLE_ctl(FALSE); + else + IDLE_ctl(TRUE); // can't idle detect fullscreen + + host_idle_init(); // host sleep event creation +#endif /* HUNTER */ + + +} + + +/* + * ========================================================================= + * + * FUNCTION : host_applInit + * + * PURPOSE : Sets up the keyboard, lpt and error panels. + * + * RETURNED STATUS : None. + * + * DESCRIPTION : Called from main.c. The keyboard and other GWI pointer + * sets are initialised here. The command line arguments are + * parsed for those flags that need processing early (ie before + * config() is called). + * + * ======================================================================= + */ +#define HOUR_BOOST_FOR_WOW 20*1000 // 20 seconds + +void host_applInit(int argc,char *argv[]) +{ + char *psz; + int temp_argc = argc; + char **temp_argv = argv; + BOOL bSwitchF = FALSE; + + working_video_funcs = &nt_video_funcs; + working_keybd_funcs = &nt_keybd_funcs; + working_mouse_funcs = &the_mouse_funcs; + + // check that someone has'nt started ntvdm from the cmd prompt. In such a + // case we should kill ntvdm as we support it only when createprocess + // executes it. We are checking a this with the argc although lots of + // fancy things can be done. If a user is bent upon running ntvdm directly + // they can always fool this code. We are only checking the presence of + // -f switch. + + +// Check if the VDM Is for WOW +// Check is for new console session + while (--temp_argc > 0) { + psz = *++temp_argv; + if (*psz == '-' || *psz == '/') { + psz++; + + if (*psz == 'f') { + bSwitchF = TRUE; + continue; + } +#ifndef MONITOR + // + // Check for windowed graphics resize + // + if (*psz == 'E') { + int i; + + i = strlen(achES); + if (!strncmp(psz, achES, i) && strlen(psz) == (size_t)i+2) { + psz += i; + BWVKey = (WORD)strtoul(psz, NULL, 16); + if (BWVKey > 0xFE) + BWVKey = 0; + } + } + else +#endif + if(tolower(*psz) == 'w'){ + VDMForWOW = TRUE; + if (bSwitchF) + break; + } + else if (*psz == 'o'){ + StreamIoSwitchOn = FALSE; + } + else if (*psz++ == 'i' && *psz) { + DosSessionId = strtoul(psz, NULL, 16); + } + + } + } + + + if (bSwitchF == FALSE) + ExitProcess (0); + + // If VDM Is for WOW keep showing the glass + if (VDMForWOW) { + if (DosSessionId) { + fSeparateWow = TRUE; + } + + ShowStartGlass (HOUR_BOOST_FOR_WOW); + StreamIoSwitchOn = FALSE; + } + else if (StreamIoSwitchOn) + enable_stream_io(); + + /* + * Get a handle to the main thread so it can be suspended during + * hand-shaking. + */ + DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &MainThread, + (DWORD) 0, + FALSE, + (DWORD) DUPLICATE_SAME_ACCESS); + + InitializeIcaLock(); + host_ica_lock(); + + init_host_uis(); /* console setup */ + nt_start_event_thread(); /* Start event processing thread */ +} + + +/* + * ========================================================================= + * + * FUNCTION : host_applClose + * + * PURPOSE : The last chance to close down. + * + * RETURNED STATUS : None. + * + * DESCRIPTION : Called from main.c. + * + * + * ======================================================================= + */ + +void +host_applClose(void) +{ + nt_remove_event_thread(); + InitSound(FALSE); + TerminateHeartBeat(); + + GfxCloseDown(); // ensure video section destroyed +#ifdef X86GFX + if (sc.ScreenBufHandle) + CloseHandle(sc.ScreenBufHandle); +#endif // X86GFX + + + + host_lpt_close_all(); /* Close all open printer ports */ + host_com_close_all(); /* Close all open comms ports */ + MouseDetachMenuItem(TRUE); /* Force the menu item away on quit */ + + DeleteConfigFiles(); // make sure temp config files are deleted +} + + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::: Closedown the VDM */ + + +/* + * host_terminate + * + * This function does not return it exits + * Most of softpc has been shutdown by the time this + * code is reached, as host_applClose has already been + * invoked. + * + */ +void host_terminate(void) +{ + +#ifdef HUNTER + if (TrapperDump != (HANDLE) -1) + CloseHandle(TrapperDump); +#endif /* HUNTER */ + + if(VDMForWOW) + ExitVDM(VDMForWOW,(ULONG)-1); // Kill everything for WOW VDM + else + ExitVDM(FALSE,0); + + ExitProcess(VdmExitCode); +} + + + +/* TerminateVDM - used by host to initiate shutdown + * + * Request to start shutting down + * + */ +VOID TerminateVDM(void) +{ + + /* + * Do base sepcific cleanup thru terminate(). + * NOTE: terminate will call host_applClose and host_terminate + * after doing base cleanup + */ + terminate(); +} + + + + + +#ifdef NOTUSEDNOTUSED +void +manager_files_init() +{ + + assert0(NO,"manager_files_init stubbed\n"); +} + + +#ifndef PROD +/* + * ========================================================================= + * + * FUNCTION : host_symb_debug_init + * + * PURPOSE : Does nothing + * + * RETURNED STATUS : None. + * + * DESCRIPTION : Called from main.c. + * + * + * ======================================================================= + */ + +void +host_symb_debug_init IFN1(char *, name) +{ +} +#endif /* nPROD */ + + +void +host_supply_dfa_filename IFN1(char *, filename) + +{ +} + +static BOOL bool_dummy_func() {} +static SHORT short_dummy_func() {} +static VOID void_dummy_func() {} + + +ERRORFUNCS dummy_error_funcs = +{ + + short_dummy_func, + short_dummy_func, + short_dummy_func + +}; + +KEYBDFUNCS dummy_keybd_funcs = +{ + + void_dummy_func, + void_dummy_func, + void_dummy_func, + void_dummy_func, + void_dummy_func, + void_dummy_func + +}; +#endif diff --git a/private/mvdm/softpc.new/host/src/nt_rez.c b/private/mvdm/softpc.new/host/src/nt_rez.c new file mode 100644 index 000000000..fd6b94a23 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_rez.c @@ -0,0 +1,187 @@ +#include "insignia.h" +#include "host_def.h" + +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + +FILE NAME : nt_rez.c +MODULE NAME : nt CMOS read/write routines + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MAY + ONLY BE DISCLOSED TO PERSONS EMPLOYED BY THE CUSTOMER WHO + REQUIRE A KNOWLEDGE OF THE SOFTWARE CODING TO CARRY OUT + THEIR JOB. DISCLOSURE TO ANY OTHER PERSON MUST HAVE PRIOR + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS INC. + +DESIGNER : +DATE : + +PURPOSE : + + + +The Following Routines are defined: + 1. host_read_resource + 2. host_write_resource + +========================================================================= + +AMENDMENTS : + +========================================================================= +*/ + + +#include <stdio.h> +#include <io.h> +#include <sys\types.h> +#include <fcntl.h> +#include <sys\stat.h> + +#include "xt.h" +#include "error.h" +#include "spcfile.h" +#include "timer.h" + + +/* + * Allow a suitable default for the CMOS file name. + */ + +#ifndef CMOS_FILE_NAME +#define CMOS_FILE_NAME "cmos.ram" +#endif + +long host_read_resource(int type, char *name, byte *addr, int maxsize, int display_error) +/* int type; Unused */ +/* char *name; Name of resource */ +/* byte *addr; Address to read data into */ +/* int maxsize; Max size that should be read */ +/* int display_error; Flag to control error message output */ +{ + + int file_fd; + long size=0; + char full_path[MAXPATHLEN]; + extern char *host_find_file(char *name, char *path, int disp_err); + + type = 0; // To stop unreferenced formal parameter errors + +#ifdef DELTA //STF - make change to 8.3 compatible name + if (strcmp(name, ".spcprofile") == 0) + name = "profile.spc"; +#endif + + file_fd = _open(host_find_file (name, full_path, display_error), O_RDONLY|O_BINARY); + + if (file_fd != -1) /* Opened successfully */ { + /* seek to end to get size */ + size = _lseek (file_fd, 0L, 2); + + if (size > maxsize) // corrupted file??? + return(0); + + /* Seek back to start before reading! */ + _lseek (file_fd, 0L, 0); + + _read(file_fd,addr,size); + _close(file_fd); + } + + return (size); +} + + + +/********************************************************/ + +void host_write_resource(type,name,addr,size) +int type; /* Unused */ +char *name; /* Name of resource */ +byte *addr; /* Address of data to write */ +long size; /* Quantity of data to write */ +{ + int file_fd; + char full_path[MAXPATHLEN]; + char *hff_ret; + extern char *host_find_file(char *name, char *path, int disp_err); + + type = 0; // To stop unreferenced formal parameter errors + + host_block_timer (); + +#ifdef DELTA //STF - make change to 8.3 compatible name + if (strcmp(name, ".spcprofile") == 0) + name = "profile.spc"; +#endif + + hff_ret = host_find_file (name,full_path,SILENT); + + if (hff_ret != NULL) + { + file_fd = _open (hff_ret,O_WRONLY); + + if (file_fd != -1) + { + _write (file_fd, addr, size); + _close (file_fd); + } + else + { + +#ifndef HUNTER + host_error (EG_REZ_UPDATE,ERR_CONT,name); +#endif + + /* Continuing => try to create a new file */ + file_fd = _open(name,O_RDWR|O_CREAT,S_IREAD|S_IWRITE); + + if (file_fd != -1) + { + _write (file_fd, addr, size); + _close (file_fd); + } + +#ifndef HUNTER + else + { + /* Tell the user we cannot update */ + host_error (EG_NO_REZ_UPDATE, ERR_CONT, CMOS_FILE_NAME); + } +#endif + + } + } + else + { + /* host find file has failed and we have + * reached this point with no error panels + */ + +#ifndef HUNTER + host_error (EG_REZ_UPDATE,(ERR_QUIT|ERR_CONT),name); +#endif + + /* Continuing => try to create a new file */ + file_fd = _open(name,O_RDWR|O_CREAT,S_IREAD|S_IWRITE); + + if (file_fd != -1) + { + _write (file_fd, addr, size); + _close (file_fd); + } + +#ifndef HUNTER + else + { + /* Tell the user we cannot update */ + host_error (EG_NO_REZ_UPDATE, ERR_CONT, + CMOS_FILE_NAME); + } +#endif + + } + + host_release_timer (); +} diff --git a/private/mvdm/softpc.new/host/src/nt_rflop.c b/private/mvdm/softpc.new/host/src/nt_rflop.c new file mode 100644 index 000000000..ec6444f5f --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_rflop.c @@ -0,0 +1,2036 @@ +/* + * Name: nt_flop.c + * Derived From: DEC begat M88K begat NeXT finally begat Generic. + * Author: Jason Proctor + * Created On: Nov 8 1990 + * Sccs ID: 10/13/92 @(#)nt_flop.c 1.9 + * Purpose: nt real floppy server. + * + * (c)Copyright Insignia Solutions Ltd., 1990. All rights reserved. + * + * Notes: + * Updated for 3.0 base by Jerry Richemont. + * Further updated by Ian Reid to support two floppy + * drives. Support is compile time dependant on the + * standard SoftPC defines. + * + * This implementation requires that you provide a + * host_rflop_drive_type() function which knows what kind of drive(s) + * your machine has; ie returns GFI_DRIVE_TYPE_xxxx. + */ + +/********************************************************/ + +/* INCLUDES */ + +#include "nt.h" +#include "ntrtl.h" +#include "nturtl.h" +#include "ntdddisk.h" +#include "windows.h" + +#include "insignia.h" +#include "host_def.h" + + +#include <stdio.h> +#include <errno.h> +#include <sys\types.h> + +#include "xt.h" +#include CpuH +#include "trace.h" +#include "error.h" +#include "fla.h" +#include "dma.h" +#include "config.h" +#include "debug.h" +#include "lock.h" +#include "timer.h" +#include "floppy.h" +#include "cmos.h" +#include "gfi.h" + +#include "nt_uis.h" +#include "nt_reset.h" +#include "nt_fdisk.h" +/********************************************************/ + +/* DEFINES */ + +#ifdef min +#undef min +#endif +#define min(a,b) (a > b ? b : a) + +#define PC_MAX_DRIVE_TYPES 2 +#define PC_MAX_DENSITY_TYPES 2 +#define PC_MAX_FLOPPY_TYPES (PC_MAX_DRIVE_TYPES * PC_MAX_DENSITY_TYPES) + +#define PC_HEADS_PER_DISKETTE 2 +#define PC_N_VALUE 2 +#define PC_BYTES_PER_SECTOR 512 + +/* disk buffer size, in bytes */ +// KEEP SYNC WITH MAX_DISKIO_SIZE defined in nt_fdisk.c +#define BS_DISK_BUFFER_SIZE 0x9000 + +/* double stepping factor */ +#define DOUBLE_STEP_FACTOR 1 + +/* density types */ +#define DENSITY_LOW 0 +#define DENSITY_HIGH 1 +#define DENSITY_EXTENDED 2 +#define DENSITY_UNKNOWN 100 +/* motor states */ +#define MOTOR_OFF 0 +#define MOTOR_ON 1 + +#ifndef PROD +#define BREAK_ON_AND 0x01 +#define BREAK_ON_OR 0x02 +#define BREAK_ON_XOR 0x03 + +UTINY break_cylinder = 0xff; +UTINY break_head = 0xff; +UTINY break_sector = 0xff; +#endif + +#ifndef PROD +DWORD rflop_dbg = 0; + +#define RFLOP_READ 0x01 +#define RFLOP_WRITE 0x02 +#define RFLOP_FORMAT 0x04 +#define RFLOP_SEEK 0x08 +#define RFLOP_READID 0x10 +#define RFLOP_RESET 0x20 +#define RFLOP_SPECIFY 0x40 +#define RFLOP_READTRACK 0x80 +#define RFLOP_RECAL 0x100 +#define RFLOP_SENSEDRV 0x200 +#define RFLOP_RATE 0x1000 +#define RFLOP_CHANGE 0x2000 +#define RFLOP_DRIVE_ON 0x4000 +#define RFLOP_DRIVE_OFF 0x8000 +#define RFLOP_OPEN 0x10000 +#define RFLOP_CLOSE 0x20000 +#define RFLOP_GUESS_MEDIA 0x40000 + +#define RFLOP_BREAK 0x80000000 + +#endif + +/********************************************************/ + +/* TYPEDEFS */ + +struct flop_struct +{ + int trks_per_disk; + int secs_per_trk; +}; + +/* + * This structure contains all the drive specific information. That is + * status which is unique to each drive, and must therefore be maintained + * on a per drive basis. + */ +typedef struct floppy_info +{ + HANDLE diskette_fd; + +/* + * drive_type - the highest density format which this drive supports, + * e.g. GFI_DRIVE_TYPE_144, GFI_DRIVE_TYPE_288 + * flop_type - the basic drive type, expressed as the lowest density + * possible for this format. For 5.25" disks this is + * GFI_DRIVE_TYPE_360, for 3.5" it is GFI_DRIVE_TYPE_720. + */ + USHORT drive_type; + USHORT flop_type; + USHORT last_seek; + USHORT last_head_seek; +/* + * Change line state. + * This is a heuristic to try to fake up the correct change line behaviour + * without having a change line. The state of the change line is returned + * as CHANGED unless the diskette motor has been continuously ON since the + * last reset. + */ + BOOLEAN change_line_state; + BOOLEAN auto_locked; + USHORT owner_pdb; + SHORT motor_state; + SHORT media_density; + USHORT max_track; + + USHORT secs_per_trk; + USHORT trks_per_disk; + DWORD align_factor; + UTINY idle_counter; + UTINY C; + UTINY H; + UTINY R; + UTINY N; + char device_name[MAX_PATH]; /* device name */ +} FL, *FLP; + +#define FLOPPY_IDLE_PERIOD 0xFF + + +/* parameter passed from main thread to FDC thread */ +typedef struct _FDC_PARMS{ +FDC_CMD_BLOCK * command_block; +FDC_RESULT_BLOCK * result_block; +USHORT owner_pdb; +BOOLEAN auto_lock; + +} FDC_PARMS, *PFDC_PARMS; + + +/********************************************************/ + + +/* routines used internally */ + +/* routines called via vector table: all the prototypes are in gfi.h +** so everybody matches. If you want to use this file to base a +** host floppy module on, you know that all the functions that must +** be declared properly for gfi to work will be. +** GM. + */ +ULONG nt_floppy_read (UTINY drive, ULONG Offset, ULONG Size, PBYTE Buffer); +ULONG nt_floppy_write (UTINY drive, ULONG Offset, ULONG Size, PBYTE Buffer); +BOOL nt_floppy_verify (UTINY drive, ULONG Offset, ULONG Size); +MEDIA_TYPE nt_floppy_get_media_type(BYTE drive, WORD cylinders, WORD sectors, WORD heads); +BOOL nt_floppy_format (UTINY drive, WORD Cylinder, WORD Head, MEDIA_TYPE media); +BOOL nt_floppy_close (UTINY drive); +BOOL nt_floppy_media_check (UTINY drive); +BOOL dismount_drive(FLP flp); + + +#ifndef PROD +VOID nt_rflop_break(VOID); +#endif + +void fdc_command_completed (BYTE drive, BYTE fdc_command); +void fdc_thread (PFDC_PARMS fdc_parms); + +BOOL nt_gfi_rdiskette_init IPT1( UTINY, drive ); +VOID nt_gfi_rdiskette_term IPT1( FLP, flp ); +SHORT nt_rflop_drive_on IPT1( UTINY, drive ); +SHORT nt_rflop_drive_off IPT1( UTINY, drive ); +SHORT nt_rflop_change IPT1( UTINY, drive ); +SHORT nt_rflop_drive_type IPT1( UTINY, drive ); +SHORT nt_rflop_rate IPT2( UTINY, drive, half_word, rate); +SHORT nt_rflop_reset IPT2( FDC_RESULT_BLOCK *, res, UTINY, drive ); +SHORT nt_rflop_command IPT2( FDC_CMD_BLOCK *, ip, FDC_RESULT_BLOCK *, res); +HANDLE nt_rdiskette_open_drive IPT1 ( UTINY, drive ); +SHORT guess_media_density IPT1 (UTINY, drive); +VOID set_floppy_parms IPT1 (FLP, flp); +BOOL dos_compatible + IPT5 (FLP, flp, UTINY, cyl, UTINY, hd, UTINY, sec, UTINY, n); +int dos_offset + IPT4 (FLP, flp, UTINY, cyl, UTINY, hd, UTINY, sec); +VOID update_chrn(FLP flp, UTINY mt, UTINY eot, UTINY sector_count); +HANDLE get_drive_handle (UTINY drive, USHORT pdb, BOOL auto_lock); +SHORT fdc_read_write ( FDC_CMD_BLOCK * ip, FDC_RESULT_BLOCK * res); +VOID floppy_close_down(USHORT, BOOL); +VOID HostFloppyReset(VOID); +VOID FloppyTerminatePDB(USHORT); +int DiskOpenRetry(CHAR); + +extern USHORT * pusCurrentPDB; + +#ifdef EJECT_FLOPPY +GLOBAL void host_floppy_eject IFN1(UTINY, drive) +#endif + + +/********************************************************/ + +/* STATIC GLOBALS */ + + +FL floppy_data[MAX_FLOPPY]; + + struct flop_struct floppy_tksc [6] = +{ + {0, 0}, /* GFI_DRIVE_TYPE_NULL */ + {40, 9}, /* GFI_DRIVE_TYPE_360 */ + {80, 15}, /* GFI_DRIVE_TYPE_12 */ + {80, 9}, /* GFI_DRIVE_TYPE_720 */ + {80, 18}, /* GFI_DRIVE_TYPE_144 */ + {80, 36} /* GFI_DRIVE_TYPE_288 */ +}; +// table used to convert GFI diskette type to NT diskette type +static MEDIA_TYPE media_table[GFI_DRIVE_TYPE_MAX] = { + Unknown, + F5_360_512, + F5_1Pt2_512, + F3_720_512, + F3_1Pt44_512, + F3_2Pt88_512 + }; + +SHORT density_state; +BOOL density_changed = TRUE; +UTINY last_drive = 0xff; +BOOL fdc_reset = FALSE; +HANDLE fdc_thread_handle = NULL; +extern UTINY number_of_floppy; +FDC_PARMS fdc_parms; +ULONG floppy_open_count = 0; + + + +/* + * Debugging info only, for non-prod cases + */ +#ifndef PROD + CHAR *cmd_name [] = +{ + "Invalid command (00)", /* 00 */ + "Invalid command (01)", /* 01 */ + "Read a Track", /* 02 */ + "Specify", /* 03 */ + "Sense Drive Status", /* 04 */ + "Write Data", /* 05 */ + "Read Data", /* 06 */ + "Recalibrate", /* 07 */ + "Sense Interrupt Status", /* 08 */ + "Write Deleted Data", /* 09 */ + "Read ID", /* 0A */ + "Invalid Command (0B)", /* 0B */ + "Read Deleted Data", /* 0C */ + "Format a Track", /* 0D */ + "Invalid Command (0E)", /* 0E */ + "Seek", /* 0F */ + "Invalid Command (10)", /* 10 */ + "Scan Equal", /* 11 */ + "Invalid Command (12)", /* 12 */ + "Invalid Command (13)", /* 13 */ + "Invalid Command (14)", /* 14 */ + "Invalid Command (15)", /* 15 */ + "Invalid Command (16)", /* 16 */ + "Invalid Command (17)", /* 17 */ + "Invalid Command (18)", /* 18 */ + "Scan Low or Equal", /* 19 */ + "Invalid Command (1A)", /* 1A */ + "Invalid Command (1B)", /* 1B */ + "Invalid Command (1C)", /* 1C */ + "Scan High or Equal", /* 1D */ + "Invalid Command (1E)", /* 1E */ + "Invalid Command (1F)", /* 1F */ +}; +#endif /* PROD */ + +char dump_buf[256]; + + +/* the disk buffer, there is only one, even though there may be two + * drives. Should be O.K. as floppy disk accesses will be single + * threaded. + */ + UTINY *disk_buffer; + +/* Report any errors in open_diskette() */ + int last_error = C_CONFIG_OP_OK; + +/********************************************************/ + +/* GLOBAL FUNCTIONS */ + +/* These functions called by config/UIF/startup now form the only +** interface between SoftPC and a floppy module. XXX_active() will +** turn the floppy emmulation in the module on by loading the global +** gfi_function_table[] with pointers to appropriate functions +** defined in this module. +** The floppy supported here is turned off by asking the empty floppy +** module to turn itself on in its place. +** +** This makes a nice orthogonal interface which keeps everything save +** the three control functions (private). The functions that are put +** in the table are defined only in gfi.h as typedefs so they are easy to +** get right. +** +** This enabling/disabling via the gfi_function_table[] does not +** take place instead of any host ioctls/opens/closes etc that are needed +** to actually open or close the device, it forms the interface for SoftPC. +** +** Really, this approach is a small tidy up of the way things are +** already done; existing host floppy code will require very small changes. +** +** GM +*/ + +/********************************************************/ + +/* Turn the floppy on and off. Off means release the driver so another +** process can use it. +*/ + +GLOBAL SHORT +host_gfi_rdiskette_active IFN3(UTINY, hostID, BOOL, active, CHAR *, err) +{ + UTINY drive = hostID - C_FLOPPY_A_DEVICE; + FLP flp = &floppy_data[drive]; + + if(active) + { + if (!nt_gfi_rdiskette_init(drive)) + { + /* Device is not a valid floppy */ + + return( C_CONFIG_NOT_VALID ); + } + return(C_CONFIG_OP_OK); + } + else + { +#ifdef EJECT_FLOPPY + host_floppy_eject(drive); +#endif /* EJECT_FLOPPY */ + nt_gfi_rdiskette_term(flp); /* shutdown process */ + gfi_empty_active(hostID,TRUE,err); /* Tell gfi 'empty' is now active */ + return(C_CONFIG_OP_OK); + } +} + +/********************************************************/ + + +/* Validate the floppy device name passed from the config system. +** Empty string is valid; it means 'no floppy'. Otherwise return OK is +** the name is 'probably' a valid device. It cannot be opened at this +** stage because if there is no floppy in the drive, the open will fail. +** +** GM. +*/ + +GLOBAL SHORT +host_gfi_rdiskette_valid IFN3(UTINY,hostID,ConfigValues *,vals,CHAR *,err) +{ +#ifndef NTVDM + UTINY cmos_byte; + UTINY drive = hostID - C_FLOPPY_A_DEVICE; + FLP flp = &floppy_data[drive]; + + if(!strcmp(vals->string,"")) + return(C_CONFIG_OP_OK); + + strcpy(flp->device_name, host_expand_environment_vars(vals->string)); + + if(!host_validate_pathname(flp->device_name)) + { + strcpy(err, host_strerror(errno)); + flp->device_name[0] = '\0'; + return( EG_MISSING_FILE ); + } + if(!host_file_is_char_dev(flp->device_name)) + { + flp->device_name[0] = '\0'; + return( EG_NOT_CHAR_DEV ); + } + + /* Check the CMOS RAM values */ + cmos_read_byte(CMOS_DISKETTE, &cmos_byte); + if (drive == 0) + cmos_byte >>= 4; + + cmos_byte &= 0xf; /* compare nibble value only */ + flp->drive_type = host_rflop_drive_type(drive); + if (cmos_byte != flp->drive_type) + vals->rebootReqd = TRUE; +#endif + return(C_CONFIG_OP_OK); +} + +/********************************************************/ + +GLOBAL VOID +host_gfi_rdiskette_change IFN2(UTINY, hostID, BOOL, apply) +{ +#ifndef NTVDM + FLP flp = &floppy_data[hostID - C_FLOPPY_A_DEVICE]; + + if (apply) + { + nt_gfi_rdiskette_term(flp); + } +#endif +} + +/********************************************************/ + +#ifdef EJECT_FLOPPY +GLOBAL void host_floppy_eject IFN1(UTINY, drive) +{ + CHAR *ebuf; + FLP flp = &floppy_data[drive]; + BOOL device_was_closed = FALSE; + + /* open the device */ + if (flp->diskette_fd == INVALID_HANDLE_VALUE) + { + device_was_closed = TRUE; + (void) nt_rdiskette_open_drive(drive); + } + + /* Do the ioctl, put your ioctl here + + if (ioctl(flp->diskette_fd, SMFDEJECT) < 0) + { + ebuf = host_strerror(errno); + assert1(NO, "host_eject_floppy: %s", ebuf); + }*/ + + /* Close the device if it wasn't open */ + + if (device_was_closed) + { + nt_gfi_rdiskette_term(flp); + } + else + { + /* Line change ONLY if device was actively open */ + flp->change_line_state = TRUE; + } +} + +#endif /* EJECT_FLOPPY */ + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: FLOPPY heart beat call ::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +GLOBAL void host_flpy_heart_beat(void) +{ + + UTINY drive; + FLP flp; + + if (pFDAccess && *pFDAccess) { + if (floppy_open_count) { + for (drive = 0; drive < number_of_floppy; drive++) { + flp = & floppy_data[drive]; + if (flp->diskette_fd != INVALID_HANDLE_VALUE && + --flp->idle_counter == 0) { + nt_floppy_close(drive); + + } + } + + } + if (number_of_fdisk != 0) + fdisk_heart_beat(); + } +} + + + + +/********************************************************/ + +/* initialise GFI function table */ +BOOL nt_gfi_rdiskette_init IFN1(UTINY, drive) +{ + FLP flp; + DISK_GEOMETRY disk_geometry[20]; + ULONG media_types; + CHAR DeviceName[] = "\\\\.\\A:"; + NTSTATUS status; + IO_STATUS_BLOCK io_status_block; + FILE_ALIGNMENT_INFORMATION align_info; + + flp = &floppy_data[drive]; + flp->diskette_fd = INVALID_HANDLE_VALUE; + + DeviceName[4] += drive; + strcpy(flp->device_name, (const char *)DeviceName); + /* + * Initialise the floppy on the required drive: + * + * 0 - Drive A, 1 - Drive B + */ + + flp->drive_type = GFI_DRIVE_TYPE_NULL; + /* open the device */ + if ((flp->diskette_fd = nt_rdiskette_open_drive (drive)) == NULL) { + return FALSE; + } + // get alignment factor + status = NtQueryInformationFile(flp->diskette_fd, + &io_status_block, + &align_info, + sizeof(FILE_ALIGNMENT_INFORMATION), + FileAlignmentInformation + ); + if (!NT_SUCCESS(status)) { + nt_gfi_rdiskette_term(flp); + return(FALSE); + } + flp->align_factor = align_info.AlignmentRequirement; + if (flp->align_factor > max_align_factor) + max_align_factor = flp->align_factor; + + + // enumerate possible supported media for this drive + // to figure out the drive type. + status = NtDeviceIoControlFile(flp->diskette_fd, + NULL, + NULL, + NULL, + &io_status_block, + IOCTL_DISK_GET_MEDIA_TYPES, + NULL, + 0L, + (PVOID)&disk_geometry, + sizeof(disk_geometry) + ); + if (!NT_SUCCESS(status)) { + nt_gfi_rdiskette_term(flp); + return FALSE; + } + nt_gfi_rdiskette_term(flp); + media_types = io_status_block.Information / sizeof(DISK_GEOMETRY); + + for (; media_types != 0; media_types--) { + switch (disk_geometry[media_types - 1].MediaType) { + case F5_360_512: + if (flp->drive_type != GFI_DRIVE_TYPE_12) + flp->drive_type = GFI_DRIVE_TYPE_360; + break; + case F5_1Pt2_512: + flp->drive_type = GFI_DRIVE_TYPE_12; + break; + case F3_720_512: + if (flp->drive_type != GFI_DRIVE_TYPE_144 && + flp->drive_type != GFI_DRIVE_TYPE_288) + flp->drive_type = GFI_DRIVE_TYPE_720; + break; + case F3_1Pt44_512: + if (flp->drive_type != GFI_DRIVE_TYPE_288) + flp->drive_type = GFI_DRIVE_TYPE_144; + break; + case F3_2Pt88_512: + flp->drive_type = GFI_DRIVE_TYPE_288; + break; + } + } + if (flp->drive_type == GFI_DRIVE_TYPE_NULL) + return FALSE; + /* configure its vectors here */ + gfi_function_table[drive].command_fn = nt_rflop_command; + gfi_function_table[drive].drive_on_fn = nt_rflop_drive_on; + gfi_function_table[drive].drive_off_fn = nt_rflop_drive_off; + gfi_function_table[drive].reset_fn = nt_rflop_reset; + gfi_function_table[drive].high_fn = nt_rflop_rate; + gfi_function_table[drive].drive_type_fn= nt_rflop_drive_type; + gfi_function_table[drive].change_fn = nt_rflop_change; + flp->C = flp->H = 0; + flp->R = 1; + flp->N = PC_N_VALUE; + flp->auto_locked = FALSE; + flp->owner_pdb = 0; + return TRUE; +} + +/********************************************************/ + +/* reset GFI function table */ +/* currently drive is ignored */ +VOID nt_gfi_rdiskette_term IFN1(FLP, flp) +{ + + // NtOpenFile returns NULL if we can not open a handle + // while win32 OpenFile/CreateFile returns INVALID_HANDLE_VALUE + // if failed to open/create the file. + if (flp->diskette_fd != NULL) + { +// host_clear_lock(flp->diskette_fd); + NtClose(flp->diskette_fd); + flp->diskette_fd = INVALID_HANDLE_VALUE; + } +} + +/********************************************************/ + +/* open the floppy device file */ +HANDLE nt_rdiskette_open_drive IFN1(UTINY, drive) +{ + + CHAR NtDeviceName[] = "\\DosDevices\\A:"; + PUNICODE_STRING Unicode; + ANSI_STRING DeviceNameA; + NTSTATUS Status; + OBJECT_ATTRIBUTES FloppyObj; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE fd; + + NtDeviceName[12] += drive; + + RtlInitAnsiString( &DeviceNameA, NtDeviceName); + + Unicode = &NtCurrentTeb()->StaticUnicodeString; + + Status = RtlAnsiStringToUnicodeString(Unicode, + &DeviceNameA, + FALSE + ); + if ( !NT_SUCCESS(Status) ) + return NULL; + + + InitializeObjectAttributes( + &FloppyObj, + Unicode, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + Status = NtOpenFile( + &fd, + (ACCESS_MASK) FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &FloppyObj, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + + if (!NT_SUCCESS(Status)) + return NULL; + else + return fd; + +} + + +ULONG nt_floppy_read(BYTE drive, ULONG Offset, ULONG Size, PBYTE Buffer) +{ + HANDLE fd; + LARGE_INTEGER large_integer; + + fd = get_drive_handle(drive, *pusCurrentPDB, FALSE); + + if (fd == INVALID_HANDLE_VALUE) + return 0; + large_integer.LowPart = Offset; + large_integer.HighPart = 0; + return(disk_read(fd, &large_integer, Size, Buffer)); +} + + +ULONG nt_floppy_write(BYTE drive, ULONG Offset, ULONG Size, PBYTE Buffer) +{ + HANDLE fd; + LARGE_INTEGER large_integer; + ULONG size_returned; + + fd = get_drive_handle(drive, *pusCurrentPDB, TRUE); + if (fd == INVALID_HANDLE_VALUE) + return 0; + + large_integer.LowPart = Offset; + large_integer.HighPart = 0; + size_returned = disk_write(fd, &large_integer, Size, Buffer); + return (size_returned); +} + +BOOL nt_floppy_format(BYTE drive, WORD Cylinder, WORD Head, MEDIA_TYPE Media) +{ + FORMAT_PARAMETERS fmt; + WORD bad_track; + ULONG size_returned; + HANDLE fd; + BOOL result; + + result = FALSE; + fmt.MediaType = Media; + fmt.StartHeadNumber = fmt.EndHeadNumber = Head; + fmt.StartCylinderNumber = fmt.EndCylinderNumber = Cylinder; + fd = get_drive_handle(drive, *pusCurrentPDB,TRUE); + if (fd == INVALID_HANDLE_VALUE) + return FALSE; + result = DeviceIoControl(fd, + IOCTL_DISK_FORMAT_TRACKS, + (PVOID) &fmt, + sizeof(fmt), + &bad_track, + sizeof(bad_track), + &size_returned, + NULL + ); + return result; +} + +// for floppy, the ioctl call DISK_VERIFY doesn't work +// we have to use read for verification +BOOL nt_floppy_verify(BYTE drive, DWORD Offset, DWORD Size) +{ + HANDLE fd; + LARGE_INTEGER large_integer; + + fd = get_drive_handle(drive, *pusCurrentPDB, FALSE); + if (fd != INVALID_HANDLE_VALUE) { + large_integer.LowPart = Offset; + large_integer.HighPart = 0; + return(disk_verify(fd, + &large_integer, + Size + )); + } + else + return FALSE; +} + +int DiskOpenRetry(char chDrive) +{ + char FormatString[32]; + char DriveLetter[32]; + + if (!LoadString(GetModuleHandle(NULL), ED_DRIVENUM, + FormatString,sizeof(FormatString)) ) + { + strcpy(FormatString,"Drive %c: "); + } + sprintf(DriveLetter, FormatString, chDrive); + return(RcMessageBox(ED_LOCKDRIVE, DriveLetter, NULL, + RMB_ABORT | RMB_RETRY | RMB_IGNORE | RMB_ICON_BANG + )); +} + + +HANDLE get_drive_handle(UTINY drive, USHORT pdb, BOOL auto_lock) +{ + FLP flp; + DWORD share_access; + + + flp = &floppy_data[drive]; + // assign new alignment factor and grab the buffer + cur_align_factor = flp->align_factor; + if ((disk_buffer = get_aligned_disk_buffer()) == NULL) + return (INVALID_HANDLE_VALUE); + + + if (flp->diskette_fd != INVALID_HANDLE_VALUE && + (fdc_reset || (auto_lock && !flp->auto_locked) || + flp->owner_pdb != pdb)) + { + nt_floppy_close(drive); + fdc_reset = FALSE; + } + share_access = auto_lock ? FILE_SHARE_READ : + FILE_SHARE_READ | FILE_SHARE_WRITE; + while(flp->diskette_fd == INVALID_HANDLE_VALUE) { + flp->diskette_fd = CreateFile ((const char *)flp->device_name, + GENERIC_READ | GENERIC_WRITE, + share_access, + NULL, + OPEN_EXISTING, + 0, + 0 + ); + if (flp->diskette_fd != INVALID_HANDLE_VALUE) { + floppy_open_count++; + flp->auto_locked = auto_lock; + flp->owner_pdb = pdb; + (*(pFDAccess))++; + break; + } + if (auto_lock && GetLastError() == ERROR_SHARING_VIOLATION && + DiskOpenRetry((char)(drive + (UTINY)'A')) == RMB_RETRY) + continue; + else + break; + + } + flp->idle_counter = FLOPPY_IDLE_PERIOD; + return (flp->diskette_fd); +} + + + +VOID HostFloppyReset(VOID) +{ + FloppyTerminatePDB((USHORT)0); +} + +VOID FloppyTerminatePDB(USHORT PDB) +{ + UTINY drive; + FLP flp; + + if (floppy_open_count) { + for (drive = 0; drive < number_of_floppy; drive++) { + flp = &floppy_data[drive]; + if (flp->diskette_fd != INVALID_HANDLE_VALUE && + (PDB == 0 || flp->owner_pdb == PDB)) + nt_floppy_close(drive); + } + + } +} + +BOOL nt_floppy_close(UTINY drive) +{ + FLP flp; + flp = &floppy_data[drive]; + +#ifndef PROD + if (rflop_dbg & RFLOP_CLOSE) + sprintf(dump_buf, "Close drive %C: handle\n", drive + 'A'); + OutputDebugString(dump_buf); +#endif + + if (flp->diskette_fd != INVALID_HANDLE_VALUE) { + CloseHandle(flp->diskette_fd); + flp->diskette_fd = INVALID_HANDLE_VALUE; + (*(pFDAccess))--; + flp->auto_locked = FALSE; + flp->owner_pdb = 0; + floppy_open_count--; + } + density_changed = TRUE; + return TRUE; +} + + +MEDIA_TYPE +nt_floppy_get_media_type +( +BYTE drive, +WORD cylinders, +WORD sectors, +WORD heads +) +{ + FLP flp; + USHORT index; + + flp = &floppy_data[drive]; + if (heads == 2){ + index = flp->drive_type; + switch (index) { + case GFI_DRIVE_TYPE_12: + if (cylinders == floppy_tksc[index].trks_per_disk && + sectors == floppy_tksc[index].secs_per_trk) + break; + index = GFI_DRIVE_TYPE_360; + + case GFI_DRIVE_TYPE_360: + if (cylinders != floppy_tksc[index].trks_per_disk || + sectors != floppy_tksc[index].secs_per_trk) + index = GFI_DRIVE_TYPE_NULL; + break; + + case GFI_DRIVE_TYPE_288: + if (cylinders == floppy_tksc[index].trks_per_disk && + sectors == floppy_tksc[index].secs_per_trk) + break; + index = GFI_DRIVE_TYPE_144; + + case GFI_DRIVE_TYPE_144: + if (cylinders == floppy_tksc[index].trks_per_disk && + sectors == floppy_tksc[index].secs_per_trk) + break; + index = GFI_DRIVE_TYPE_720; + + case GFI_DRIVE_TYPE_720: + if (cylinders == floppy_tksc[index].trks_per_disk && + sectors == floppy_tksc[index].secs_per_trk) + break; + default: + index = GFI_DRIVE_TYPE_NULL; + } + } + else + index = GFI_DRIVE_TYPE_NULL; + return(media_table[index]); + +} + +BOOL nt_floppy_media_check (UTINY drive) +{ + FLP flp; + ULONG size_returned; + + flp = &floppy_data[drive]; + if (flp->diskette_fd == INVALID_HANDLE_VALUE) + return FALSE; + return(DeviceIoControl(flp->diskette_fd, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + &size_returned, + NULL + )); +} + +/********************************************************/ + +/* perform an FDC command */ + SHORT +nt_rflop_command + IFN2(FDC_CMD_BLOCK *, command_block, FDC_RESULT_BLOCK *,result_block) +{ + UTINY drive; + FLP flp; + BOOL failed = FALSE; + UTINY C, H, N, S, D; + DWORD fdc_thread_id; + BYTE fdc_command; + BOOL auto_lock; + + + note_trace1 (GFI_VERBOSE, "FDC: %s command", + cmd_name [get_type_cmd (command_block)]); + + drive = get_type_drive(command_block); + + flp = &floppy_data[drive]; + flp->idle_counter = FLOPPY_IDLE_PERIOD; + + /* Clear result status registers */ + put_r0_ST0 (result_block, 0); + put_r0_ST1 (result_block, 0); + put_r0_ST2 (result_block, 0); + + fdc_command = get_type_cmd(command_block); + /* for those commands which need a valid floppy be inserted + we may have to create an independent thread to perform + the real operation if there is currenly no media + in the drive. The reason of this independent thread is that + the FDC is always in its execution phase even though there is + not media in the drive. As soon as you insert a media(bad or + good), it then performs its operation, terminates the phase, + raises interrupt and enters result phase. Some applications just + do a read id and then wait the interrupt to occur no matter how + long the user will take to insert a media. To do this I broke up + the fdc_command routine so that both main and the fdc thread can + use the same code. There is not a good point that we can close the + thread handle as soon as it terminated. Therefore, we close the + handle on next fdc command + */ + if (fdc_thread_handle != NULL) { + CloseHandle(fdc_thread_handle); + fdc_thread_handle = NULL; + } + + if ( (auto_lock = (fdc_command == FDC_WRITE_DATA || fdc_command == FDC_FORMAT_TRACK)) || + fdc_command == FDC_READ_DATA || + fdc_command == FDC_READ_ID || + fdc_command == FDC_READ_TRACK) { + // this might fail due to media changed and from FDC point of + // view, media change is meaningless. Therefore, we close the + // handle to the drive and reopen it so that the file system + // will mount a new volume for us. Then we check the the + // media again. If it still fails, we are sure that there is + // no media in the drive so we go ahead to create a thread. + if (!nt_floppy_media_check(drive)) { + nt_floppy_close(drive); + get_drive_handle(drive, *pusCurrentPDB, auto_lock); + if (!nt_floppy_media_check(drive)) { + fdc_parms.auto_lock = auto_lock; + fdc_parms.command_block = command_block; + fdc_parms.result_block = result_block; + fdc_parms.owner_pdb = *pusCurrentPDB; + fdc_thread_handle = CreateThread(NULL, + 0, + (LPTHREAD_START_ROUTINE)fdc_thread, + (PVOID)&fdc_parms, + 0, + &fdc_thread_id + ); + return FAILURE; + } + else { // media changed + fdc_read_write(command_block, result_block); + return SUCCESS; + } + + } + else { + fdc_read_write(command_block, result_block); + return SUCCESS; + } + } + + /* get disk bumpf */ + C = get_c0_cyl (command_block); + H = get_c0_hd (command_block); + S = get_c0_sector (command_block); + N = get_c0_N (command_block); + + /* block timer to prevent interrupted system calls */ + host_block_timer (); + + switch (get_type_cmd (command_block)) + { + + case FDC_SPECIFY: +#ifndef PROD + if (rflop_dbg & RFLOP_SPECIFY) { + OutputDebugString("Specify\n"); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + break; + + + case FDC_SENSE_DRIVE_STATUS: + +#ifndef PROD + if (rflop_dbg & RFLOP_SENSEDRV) + OutputDebugString("Sense Drive Status\n"); +#endif + D = get_c7_drive (command_block); + put_r2_ST3_fault (result_block,0); + put_r2_ST3_ready (result_block,1); + put_r2_ST3_track_0 (result_block,(flp->last_head_seek == 0?1:0)); + put_r2_ST3_two_sided (result_block,1); + put_r2_ST3_head_address (result_block,0); + put_r2_ST3_unit (result_block,D); + break; + + /* RECALIBRATE and SEEK do not really return any results */ + /* However, we return results here which are used by gfi.c */ + /* to construct the results for any following SenseInterruptStatus command */ + case FDC_RECALIBRATE: + +#ifndef PROD + if (rflop_dbg & RFLOP_RECAL) + OutputDebugString("Recalibrate\n"); +#endif + D = get_c5_drive (command_block); + put_r3_ST0 (result_block,0); + put_r1_ST0_int_code (result_block,0); + put_r1_ST0_seek_end (result_block,1); + put_r1_ST0_unit (result_block,D); + put_r3_PCN (result_block,0); + flp->last_seek = flp->last_head_seek = 0; + flp->C = 0; + break; + + case FDC_SEEK: + + D = get_c8_drive (command_block); + C = get_c8_new_cyl (command_block); + +#ifndef PROD + if (rflop_dbg & RFLOP_SEEK) { + sprintf(dump_buf, "Seek: D C = %d %d \n", D, C); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + put_r3_ST0(result_block,0); + put_r1_ST0_head_address(result_block,1); + put_r1_ST0_seek_end(result_block,1); + put_r1_ST0_int_code(result_block,0); + put_r1_ST0_unit(result_block,D); + put_r3_PCN(result_block,C); + flp->last_seek = C; + flp->last_head_seek = min(flp->last_seek,flp->max_track); + flp->C = C; + break; + + default: + +#ifndef PROD + sprintf(dump_buf, "Receive unsupported command: command = %d\n", + get_type_cmd(command_block)); + OutputDebugString(dump_buf); +#endif + + put_r0_ST0 (result_block, 0); + put_r1_ST0_int_code (result_block, 2); + + note_trace1 (GFI_VERBOSE,"FDC: Unimplemented command, type %d", + get_type_cmd (command_block)); + } + + +#ifndef PROD + if (io_verbose & GFI_VERBOSE) { + fprintf(trace_file, + "FDC: results %02x %02x %02x %02x %02x %02x %02x\n\n", + result_block[0], result_block[1], result_block[2], + result_block[3], result_block[4], result_block[5], + result_block[6]); + } +#endif /* !PROD */ + + host_release_timer (); + + return SUCCESS; +} + +/********************************************************/ + +/* turn the motor on */ +SHORT +nt_rflop_drive_on IFN1(UTINY, drive) +{ + FLP flp = &floppy_data[drive]; + + note_trace0 (GFI_VERBOSE, "FDC: Drive on command"); +#ifndef PROD + if (rflop_dbg & RFLOP_DRIVE_ON) { + sprintf(dump_buf, "drive on: drive = %d\n", drive); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + if (drive >= number_of_floppy) + { + note_trace1 (GFI_VERBOSE, + "FDC: Invalid drive %d accessed", drive); + + return (FAILURE); + } + + flp->motor_state = MOTOR_ON; + + return (SUCCESS); +} + +/********************************************************/ + +/* turn the motor off */ +SHORT +nt_rflop_drive_off IFN1(UTINY, drive) +{ + FLP flp = &floppy_data[drive]; + note_trace0 (GFI_VERBOSE, "FDC: Drive off command"); +#ifndef PROD + if (rflop_dbg & RFLOP_DRIVE_OFF) { + sprintf(dump_buf, "drive off: drive = %d\n", drive); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + if (drive >= number_of_floppy) + { + note_trace1 (GFI_VERBOSE, + "FDC: Invalid drive %d accessed", drive); + + return (FAILURE); + } + + flp->motor_state = MOTOR_OFF; + + /* I believe the line below makes booting off of low density + * diskettes problematical, particularly after restarts. + * Make your own mind up, the DEC code does it, the Sparc + * doesn't (as at 11/9/92) +// we have no reason to do so in NT. As far as change line concerned, +// the file system will tell us "media has been changed" when we ask +// it to do some real work. +// flp->change_line_state = TRUE; + */ + + return (SUCCESS); +} + +/********************************************************/ + +/* set the data transfer rate + * This controls the "density" of the floppy: the rate MUST + * match the actual media density for the disk controller to + * be able to read the sectors. + */ +SHORT +nt_rflop_rate IFN2(UTINY, drive, half_word, rate) +{ + short new_density; +// basically, "set rate applied to every drive since we have +// only one FDC(and mutiple drive). + +#if 0 + FLP flp = &floppy_data[drive]; + + switch (rate) + { + /* 2.88M high-density floppies */ + case DCR_RATE_1000: + + flp->density_state = DENSITY_EXTENDED; + set_floppy_parms (flp); + break; + + /* 1.2M or 1.44M high-density floppies */ + case DCR_RATE_500: + + flp->density_state = DENSITY_HIGH; + set_floppy_parms (flp); + break; + + /* 360K or 720K low-density floppies */ + case DCR_RATE_250: + case DCR_RATE_300: + + flp->density_state = DENSITY_LOW; + set_floppy_parms (flp); + break; + + /* crapola density passed */ + default: + + return FAILURE; + } + note_trace2 (GFI_VERBOSE, "FDC: Set rate %0x => density %d", + rate, flp->density_state); + /* read floppy's boot sector */ + /* to determine the real density */ +// guess_media_density (drive); +#endif +#ifndef PROD + if (rflop_dbg & RFLOP_RATE) { + sprintf(dump_buf, "set rate: rate = %d\n", rate); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + switch (rate) { + case DCR_RATE_1000: + new_density = DENSITY_EXTENDED; + break; + case DCR_RATE_500: + new_density = DENSITY_HIGH; + break; + case DCR_RATE_300: + case DCR_RATE_250: + new_density = DENSITY_LOW; + break; + default: + return FAILURE; + + } + if (new_density != density_state) { + density_state = new_density; + density_changed = TRUE; + } + return SUCCESS; +} + + +/********************************************************/ + +/* return the state of the change line */ +SHORT +nt_rflop_change IFN1(UTINY, drive) +{ + FLP flp = &floppy_data[drive]; + note_trace1 (GFI_VERBOSE, "FDC: change_line %c", + flp->change_line_state? 'T':'F'); + + // if fla has been reset or the current change line is on(no media), + // close the drive and reopen it. This is done because + // nt_floppy_media_check(IOCTL_DISK_CHECK_VERIFY) will continue + // to report media change even the users have a new disketter inserted. + // + if (fdc_reset || flp->change_line_state) { + fdc_reset = FALSE; + nt_floppy_close(drive); + } + get_drive_handle(drive, *pusCurrentPDB, FALSE); + flp->change_line_state = !nt_floppy_media_check(drive); + +#ifndef PROD + if (rflop_dbg & RFLOP_CHANGE) { + sprintf(dump_buf, "Check Change Line: line = %d\n", flp->change_line_state); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + return(flp->change_line_state); +} + +/********************************************************/ + +/* return the type of the drive */ +SHORT +nt_rflop_drive_type IFN1(UTINY, drive) +{ + FLP flp = &floppy_data[drive]; + + +/* setup base media type depending on drive type */ +// I don't understand why we have to do this stuff every time. + switch (flp->drive_type) + { + /* 5.25" drives */ + case GFI_DRIVE_TYPE_360: + case GFI_DRIVE_TYPE_12: + + flp->flop_type = GFI_DRIVE_TYPE_360; + break; + + /* 3.5" drives */ + case GFI_DRIVE_TYPE_720: + case GFI_DRIVE_TYPE_144: + case GFI_DRIVE_TYPE_288: + + flp->flop_type = GFI_DRIVE_TYPE_720; + break; + + default: + break; + } + + set_floppy_parms(flp); + note_trace2 (GFI_VERBOSE, "FDC: flop_type %d density %d", + flp->flop_type, flp->drive_type - flp->flop_type); + + return (flp->drive_type); +} + +/********************************************************/ + +/* close and reopen the device */ +SHORT +nt_rflop_reset IFN2(FDC_RESULT_BLOCK *, result_block, UTINY, drive) +{ + FLP flp = &floppy_data[drive]; + + note_trace0 (GFI_VERBOSE, "FDC: Reset command"); + +#ifndef PROD + if (rflop_dbg & RFLOP_RESET) { + OutputDebugString("reset\n"); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + /* clear change line */ + flp->change_line_state = FALSE; + fdc_reset = TRUE; + + if (fdc_thread_handle) { // signal thread to exit + CloseHandle(fdc_thread_handle); + fdc_thread_handle = NULL; + } + return (SUCCESS); +} + + +// this is the independent thread which performs FDC operation. +// this thread is not created from the beginning, instead, it was +// created on demand. +void fdc_thread(PFDC_PARMS fdc_parms) +{ + BYTE drive, fdc_command; + FDC_CMD_BLOCK * command_block; + BOOL auto_lock; + USHORT pdb; + command_block = fdc_parms->command_block; + auto_lock = fdc_parms->auto_lock; + pdb = fdc_parms->owner_pdb; + drive = get_type_drive(command_block); + fdc_command = get_type_cmd(command_block); + while (TRUE) { + // if there is media inserted, perform the operation + // and enter result phase. + if (get_drive_handle(drive, pdb, auto_lock) != INVALID_HANDLE_VALUE && + nt_floppy_media_check(drive)) { + // force the file system to remount the volume + nt_floppy_close(drive); + // and then perform the operation + fdc_read_write (command_block, fdc_parms->result_block); + // raise an interrupt + fdc_command_completed(drive, fdc_command); + break; + } + // if reset happen, quit + if (fdc_thread_handle == NULL) + break; + } +} + +SHORT +fdc_read_write ( +FDC_CMD_BLOCK * command_block, +FDC_RESULT_BLOCK * result_block +) +{ + + USHORT transfer_count; /* Surely counts cannot be negative? GM */ + FLP flp; + BOOL failed = FALSE; + UTINY C, H, N, S, D, drive, fdc_command; + USHORT dma_size; + ULONG transfer_size; + ULONG transferred_size; + long transfer_start; + sys_addr dma_address; + + drive = get_type_drive(command_block); + fdc_command = get_type_cmd(command_block); + + /* get disk bumpf */ + C = get_c0_cyl (command_block); + H = get_c0_hd (command_block); + S = get_c0_sector (command_block); + N = get_c0_N (command_block); + + flp = &floppy_data[drive]; + /* block timer to prevent interrupted system calls */ + host_block_timer (); + if (fdc_command != FDC_FORMAT_TRACK) { + if ((density_changed || drive != last_drive) && + guess_media_density(drive) != DENSITY_UNKNOWN) { + set_floppy_parms(flp); + density_changed = FALSE; + last_drive = drive; + } + if (density_state != flp->media_density) { + put_r0_ST0 (result_block, 0x40); + put_r0_ST1 (result_block, 0); + put_r1_ST1_no_address_mark (result_block,1); + put_r0_ST2 (result_block, 0); +#ifndef PROD + sprintf(dump_buf, "density mismatch: %d <-> %d\n", density_state, + flp->media_density); + OutputDebugString(dump_buf); +#endif + goto fdc_read_write_exit; + } + } + + + /* + * Do common setup processing, if read or write + */ + if (fdc_command == FDC_READ_DATA || + fdc_command == FDC_WRITE_DATA) { + /* + * Find out how much gunk to transfer + */ + dma_enquire (DMA_DISKETTE_CHANNEL, &dma_address, &dma_size); + transfer_size = dma_size + 1; +#ifndef PROD + if (transfer_size > BS_DISK_BUFFER_SIZE) + always_trace2("FDC: transfer size ( %d ) greater than disk buffer size %d\n", transfer_size, BS_DISK_BUFFER_SIZE); +#endif /* PROD */ + /* check params passed are DOS compatible */ + if (! dos_compatible (flp, C, H, S, N) || + density_state != flp->media_density) { + sprintf(dump_buf, "Incompatible DOS diskette, C H R N = %d %d %d %d\n", + C, H, S, N); + OutputDebugString(dump_buf); +// do not pop up this annoy message because some applications are simply +// "probing" the diskette. We just fail the call. +// host_direct_access_error((ULONG) NOSUPPORT_FLOPPY); +#ifndef PROD + + if (!dos_compatible (flp, C, H, S, N)) { + note_trace0 (GFI_VERBOSE, + "Refused: not DOS compatible"); + } + if (density_state != flp->media_density) { + note_trace0 (GFI_VERBOSE, + "Refused: density mismatch"); + } +#endif /* !PROD */ + /* Sector not found or wrong size */ + put_r0_ST0 (result_block,0x40); + put_r0_ST1 (result_block,0); + if (density_state != flp->media_density) { + put_r1_ST1_no_address_mark (result_block,1); + } else { + put_r1_ST1_no_data (result_block,1); + } + put_r0_ST2 (result_block,0); + goto fdc_read_write_exit; + } + /* work out start position on floppy and sector count */ + transfer_start = dos_offset (flp, C, H, S); + transfer_count = (USHORT)(transfer_size / PC_BYTES_PER_SECTOR); +#ifndef PROD + if (rflop_dbg & (RFLOP_READ | RFLOP_WRITE)) { + sprintf(dump_buf, "Read/Write Sector: start offset = 0x%lx\n", + transfer_start); + OutputDebugString(dump_buf); + sprintf(dump_buf, "Read/Write Sector: size = 0x%x bytes\n", transfer_size); + OutputDebugString(dump_buf); + } +#endif + + } + + switch (fdc_command) + { + case FDC_READ_DATA: +#ifndef PROD + if (rflop_dbg & RFLOP_READ) { + sprintf(dump_buf, "Read Sectors: C H R N = %d %d %d %d\n", + C, H, S, N); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + if (!failed) { + transferred_size = nt_floppy_read(drive, + transfer_start, + transfer_size, + disk_buffer + ); + if (transferred_size != transfer_size) { + last_error = GetLastError(); + sprintf(dump_buf, "Read Error, code = %lx\n", last_error); + OutputDebugString(dump_buf); + failed = TRUE; + } + else { + dma_request (DMA_DISKETTE_CHANNEL, + (char *)disk_buffer, (USHORT)transfer_size); + } + } + + if (failed){ + put_r0_ST0 (result_block, 0x40); + put_r0_ST1 (result_block, 0); + put_r1_ST1_no_data (result_block, 1); + put_r0_ST2 (result_block, 0); + } + else { + put_r0_ST0 (result_block, 0x04); + put_r0_ST1 (result_block, 0); + put_r0_ST2 (result_block, 0); + put_r1_ST0_unit (result_block, drive); + put_r1_ST0_head_address(result_block, H); + } + + flp->C = C; + flp->H = H; + flp->R = S; + flp->N = N; + update_chrn (flp, + (UTINY)(get_c0_MT(command_block)), + (UTINY)(get_c0_EOT(command_block)), + (UTINY)transfer_count + ); + /* What should these really be? */ + put_r0_cyl (result_block, flp->C); + put_r0_head (result_block, flp->H); + put_r0_sector (result_block, flp->R); + put_r0_N (result_block, flp->N); + break; + + case FDC_WRITE_DATA: +#ifndef PROD + if (rflop_dbg & RFLOP_WRITE) { + sprintf(dump_buf, "Write Sectors: C H R N = %d %d %d %d\n", + C, H, S, N); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + if (!failed) { + /* copy from Intel space */ + dma_request (DMA_DISKETTE_CHANNEL, (char *) disk_buffer, + (USHORT)transfer_size); + transferred_size = nt_floppy_write(drive, + transfer_start, + transfer_size, + disk_buffer + ); + if (transferred_size != transfer_size) { + last_error = GetLastError(); + sprintf(dump_buf, "Write Error, code = %lx\n", last_error); + OutputDebugString(dump_buf); + failed = TRUE; + } + } + + /* Clear down result bytes */ + put_r0_ST0 (result_block, 0); + put_r0_ST1 (result_block, 0); + put_r0_ST2 (result_block, 0); + + if (failed) + { + put_r1_ST0_int_code (result_block, 1); + + /* make sure we get the correct error for EROFS */ + if (last_error == ERROR_WRITE_PROTECT) + put_r1_ST1_write_protected (result_block, 1); + else + put_r1_ST1_no_data (result_block, 1); + } + else + { + put_r1_ST0_head_address (result_block, H); + put_r1_ST0_unit(result_block, drive); + } + + flp->C = C; + flp->H = H; + flp->R = S; + flp->N = N; + + update_chrn (flp, + (UTINY)(get_c1_MT(command_block)), + (UTINY)(get_c1_EOT(command_block)), + (UTINY)transfer_count + ); + put_r0_cyl (result_block, flp->C); + put_r0_head (result_block, flp->H); + put_r0_sector (result_block, flp->R); + put_r0_N (result_block, flp->N); + break; + + case FDC_READ_TRACK: +#ifndef PROD + if (rflop_dbg & RFLOP_READTRACK) { + OutputDebugString("Read Tracks\n"); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + + break; + + case FDC_FORMAT_TRACK: + + dma_enquire (DMA_DISKETTE_CHANNEL, &dma_address, &dma_size); + transfer_size = dma_size + 1; + /* copy from Intel space */ + dma_request (DMA_DISKETTE_CHANNEL, (char *) disk_buffer, + (USHORT)transfer_size); + + D = get_c8_drive(command_block); + H = get_c8_head(command_block); + flp = &floppy_data[D]; +#ifndef PROD + if (rflop_dbg & RFLOP_FORMAT) { + sprintf(dump_buf, "Format Track: C H Media = %d %d %d \n", + flp->last_seek, H, flp->flop_type + density_state); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + if (!nt_floppy_format(D, + flp->last_seek, + H, + media_table[flp->flop_type + density_state] + )) { + last_error = GetLastError(); + sprintf(dump_buf, "Format Error, code = %lx\n", last_error); + OutputDebugString(dump_buf); + failed = TRUE; + } + if (!failed) { + put_r0_ST0 (result_block, 0); + put_r0_ST1 (result_block, 0); + put_r0_ST2 (result_block, 0); + // C H R N are meaningless on formatting + } + else { + put_r0_ST0 (result_block, 0x40); + put_r1_ST0_head_address (result_block, H); + put_r1_ST0_unit(result_block, D); + put_r0_ST1 (result_block, 0); + if (last_error == ERROR_WRITE_PROTECT) { + put_r1_ST1_write_protected (result_block, 1); + } + put_r0_ST2 (result_block, 0); + } + break; + + case FDC_READ_ID: + + H = get_c4_head(command_block); + /* check if cylinder number massaging required */ + if ((flp->flop_type + density_state) == GFI_DRIVE_TYPE_360) + { + /* 5.25" low density, 40 tracks */ + C = (UTINY) (flp->last_seek / 2); + put_c0_cyl (result_block, C); + + } + else + { + /* no massage required, 80 tracks */ + C = (UTINY)flp->last_seek; + put_r0_cyl (result_block, C); + + } + if (flp->C < flp->trks_per_disk) { + put_r1_ST0_unit(result_block, drive); + put_r1_ST0_head_address(result_block, H); + put_r0_head (result_block, H); + put_r0_sector (result_block, flp->R); + put_r0_N (result_block, flp->N); + C = flp->C; + put_r0_cyl(result_block, flp->C); + } + else + C = flp->trks_per_disk - 1; + + put_r0_cyl(result_block, C); +#ifndef PROD + if (rflop_dbg & RFLOP_READID) { + sprintf(dump_buf, "Read ID: C H R N = %d %d %d %d\n", + C, H, flp->R, flp->N); + OutputDebugString(dump_buf); + if (rflop_dbg & RFLOP_BREAK) + nt_rflop_break(); + } +#endif + } + + if (failed) + density_changed = TRUE; +fdc_read_write_exit: + + return SUCCESS; + +} +/********************************************************/ + +/* INTERNALLY USED FUNCTIONS */ + +/* In order to read the data on the floppy, the floppy controller must + * be set to the same density (rate) as was used to write the data. + * A mismatch in densities will cause read failures, and DOS uses these + * failures as a way to probe the diskette for the correct density. + * + * To emulate the floppy controller correctly, we must somehow + * guess the density of the media and produce fake "read failures" if the + * controller density doesn't match the media density. + * + * On the assumption that the operating system has already done this, + * and that we are looking at a DOS floppy, nt_flop.c can read the + * "total number of sectors" value from the boot sector and guess + * the density accordingly. There should be no need for this function + * if you have fairly direct access to the disk controller. + */ + int probelist[] = { 720-1, 1440-1, 2400-1, 2880-1, 5760-1, 0-1}; + + SHORT +guess_media_density IFN1(UTINY, drive) +{ + int total_sectors; + int *probe; + FLP flp; + ULONG transferred_size; + + flp = &floppy_data[drive]; + transferred_size = nt_floppy_read(drive, + 0L, + PC_BYTES_PER_SECTOR, + (PBYTE) disk_buffer + ); + + if (transferred_size != PC_BYTES_PER_SECTOR) { + last_error = GetLastError(); + OutputDebugString("Unknown Media\n"); + /* assume that the disk is unformatted */ + return(flp->media_density = DENSITY_UNKNOWN);/* impossible value */ + } + + + /* check for a DOS boot block + * + * AccessPC has shown that 0x55, 0xaa is not the only magic + * number in use, and it might be better to check the total_sectors + * number itself for a valid size. This algorithm is safe, but may + * do unnecessary disk reads if an different magic number is used. + */ + + /* the AA, 55 signature sometime doesn't work at all, It should + be done as DOS */ + + if ((disk_buffer[0] == 0x69 || disk_buffer[0] == 0xE9 || + (disk_buffer[0] == 0xEB && disk_buffer[2] == 0x90)) && + (disk_buffer[21] & 0xF0) == 0xF0 ) { + /* read total number of sectors, and thus deduce density + */ + total_sectors = disk_buffer [20] * 256 + disk_buffer [19]; + } else { + note_trace2 (GFI_VERBOSE, + "not a DOS boot block: magic = %02x %02x", + disk_buffer[510], disk_buffer[511]); + + /* probe disk by reading last sectors for each size + * (in order) until the read fails. + */ + total_sectors = 0; + for (probe=probelist; *probe != 0; probe++) { + transferred_size = nt_floppy_read(drive, + (*probe)*PC_BYTES_PER_SECTOR, + PC_BYTES_PER_SECTOR, + disk_buffer + ); + if (transferred_size != PC_BYTES_PER_SECTOR) + break; /* out of the for loop */ + total_sectors = (*probe) + 1; + } + } + + switch (total_sectors) + { + case 0: + note_trace0( GFI_VERBOSE, "total_sectors = 0 - unformatted"); + flp->media_density = DENSITY_UNKNOWN; /* impossible value */ + break; + + case 720: + case 1440: + flp->media_density = DENSITY_LOW; + break; + + case 2400: + case 2880: + flp->media_density = DENSITY_HIGH; + break; + + case 5760: + flp->media_density = DENSITY_EXTENDED; + break; + + default: + note_trace1 (GFI_VERBOSE, + "total sectors = %d? Assume high density", + total_sectors); + flp->media_density = DENSITY_HIGH; + break; + } + +#ifndef PROD + note_trace1 (GFI_VERBOSE, "guess_media_density %d", + flp->media_density); + if (flp->media_density != density_state) { + note_trace0 (GFI_VERBOSE, + "media & controller densities are incompatible!\n"); + } +#endif /* !PROD */ + return(flp->media_density); +} + +/********************************************************/ + +/* + * dos_offset() calculates the offset in bytes of the required sector + * from the start of the nt virtual disk file for a given track + * and sector. This maps the floppy data onto the nt file in an + * interleaved format with the data for each head adjacent for a + * given cylinder. + */ + +int +dos_offset IFN4(FLP, flp, UTINY, cyl, UTINY, hd, UTINY, sec) +{ + int ret; + + ret = (((cyl * PC_HEADS_PER_DISKETTE * flp->secs_per_trk) + + (hd * flp->secs_per_trk) + + (sec - 1)) * PC_BYTES_PER_SECTOR) ; + + note_trace1(GFI_VERBOSE, "Dos offset %d", ret); + return (ret); +} + +/********************************************************/ + +/* + * dos_compatible() returns TRUE if the command block's + * cylinder/head/sector is DOS-compatible + */ + +BOOL +dos_compatible IFN5(FLP, flp, UTINY, cyl, UTINY, hd, UTINY, sec, UTINY, n) +{ + BOOL ret; + + ret = ((hd <= PC_HEADS_PER_DISKETTE) + && (cyl < flp->trks_per_disk) + && (sec <= flp->secs_per_trk) + && (n == PC_N_VALUE)); + + return (ret); +} + +/********************************************************/ + +VOID +set_floppy_parms IFN1(FLP, flp) +{ + int index = flp->flop_type + density_state; + + flp->secs_per_trk = + floppy_tksc [index].secs_per_trk; + + flp->trks_per_disk = + floppy_tksc [index].trks_per_disk; + + flp->max_track = flp->trks_per_disk - 1; + note_trace2(GFI_VERBOSE, "set_floppy_parms: secs_per_trk %d, trks_per_disk %d", flp->secs_per_trk, flp->trks_per_disk); + +} + +/********************************************************/ + + +#ifndef PROD +VOID nt_rflop_break(VOID) +{ +} + +#endif + +VOID update_chrn ( +FLP flp, +UTINY mt, +UTINY eot, +UTINY sector_count +) +{ + UTINY new_sector; + +#ifndef PROD + if (flp->C == break_cylinder && + flp->H == break_head && + flp->R == break_sector) + nt_rflop_break(); +#endif + + new_sector = flp->R + sector_count - 1; + if (new_sector > eot && mt != 0) { + flp->H = 1; + new_sector >>= 1; + } + flp->R = (new_sector == eot) ? 1 : new_sector + 1; + + if (mt != 0 && new_sector == eot) { + if(flp->H == 1) + flp->C++; + flp->H ^= 1; + } + else { + if (new_sector == eot) + flp->C++; + } +} diff --git a/private/mvdm/softpc.new/host/src/nt_sas.c b/private/mvdm/softpc.new/host/src/nt_sas.c new file mode 100644 index 000000000..ff2d706ae --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_sas.c @@ -0,0 +1,148 @@ +#include "insignia.h" +#include "host_def.h" +/* + * VPC-XT Revision 1.0 + * + * Title : Sun4 SAS initialization + * + * Description : Initialize the host side of sas. + * + * Author : A. Guthrie + * + * Notes : None + */ + +static char SccsID[]="@(#)sun4_sas.c 1.3 5/7/91 Copyright Insignia Solutions Ltd."; + +#include <sys/types.h> +#include "xt.h" +#include "sas.h" +#include "debug.h" + +LOCAL UTINY *reserve_for_M = NULL; + +// +// Temporary pointer to the start of M. +// + +#ifdef SUN_VA +GLOBAL UTINY *M; +IMPORT UTINY *self_modify; +#endif + +#ifdef HOST_SAS + +#undef sas_load +#undef sas_loadw +#undef sas_store +#undef sas_storew +#undef sas_fills +#undef sas_fillsw +#undef sas_hw_at +#undef sas_w_at +#undef sas_dw_at +#undef sas_loads +#undef sas_stores +#undef sas_move_bytes_forward +#undef sas_move_words_forward +#undef sas_move_bytes_backward +#undef sas_move_words_backward +#undef get_byte_addr +#undef inc_M_ptr +#undef M_get_dw_ptr + +IMPORT VOID sas_load(); +IMPORT VOID sas_store(); +#ifdef SUN_VA +IMPORT VOID sas_loadw_swap(); +IMPORT VOID sas_storew_swap(); +#else +IMPORT VOID sas_loadw(); +IMPORT VOID sas_storew(); +#endif +IMPORT VOID sas_fills(); +IMPORT VOID sas_fillsw(); +IMPORT half_word sas_hw_at(); +IMPORT word sas_w_at(); +IMPORT double_word sas_dw_at(); +IMPORT VOID sas_loads(); +IMPORT VOID sas_stores(); +IMPORT VOID sas_move_bytes_forward(); +IMPORT VOID sas_move_words_forward(); +IMPORT VOID sas_move_bytes_backward(); +IMPORT VOID sas_move_words_backward(); +IMPORT host_addr Start_of_M_area; + +LOCAL host_addr forward_get_addr(addr) +host_addr addr; +{ + return( (host_addr)((long)Start_of_M_area + (long)addr)); +} + +LOCAL host_addr forward_inc_M_ptr(p, off) +host_addr p; +host_addr off; +{ + return( (host_addr)((long)p + (long)off) ); +} + +GLOBAL SAS_FUNCTIONS host_sas_funcs = +{ + sas_load, +#ifdef SUN_VA + sas_loadw_swap, +#else + sas_loadw, +#endif + sas_store, +#ifdef SUN_VA + sas_storew_swap, +#else + sas_storew, +#endif + sas_fills, + sas_fillsw, + sas_hw_at, + sas_w_at, + sas_dw_at, + sas_loads, + sas_stores, + sas_move_bytes_forward, + sas_move_words_forward, + sas_move_bytes_backward, + sas_move_words_backward, + forward_get_addr, + forward_inc_M_ptr, + forward_get_addr, +}; + +#endif /* HOST_SAS */ + +/* + Host_sas_init: allocate intel memory space +*/ + +#define SIXTY_FOUR_K (1024*64) /* For scratch buffer */ + +//UTINY *host_sas_init(size) +//sys_addr size; +//{ +// return(NULL); +//} + +#ifdef SUN_VA +/* This is temporary until removed from sdos.o */ +UTINY *host_as_init() +{ + assert0(NO,"host_as_init is defunct - call can be removed"); + return( 0 ); +} +#endif /* SUN_VA */ + +//UTINY *host_sas_term() +//{ +// if(reserve_for_M) free(reserve_for_M); +// +// return(reserve_for_M = NULL); +//} + diff --git a/private/mvdm/softpc.new/host/src/nt_sec.c b/private/mvdm/softpc.new/host/src/nt_sec.c new file mode 100644 index 000000000..dd0a9f818 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_sec.c @@ -0,0 +1,158 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdm.h> +#include "insignia.h" +#include "host_def.h" +#include "wchar.h" +#include "stdio.h" + +#include "ntstatus.h" +#include <ntddvdeo.h> + +#include "nt_fulsc.h" +#include "nt_det.h" +#include "nt_thred.h" +#include "nt_eoi.h" +#include "host_rrr.h" +#include "nt_uis.h" + +/* + * ========================================================================== + * Name: nt_sec.c + * Author: Jerry Sexton + * Derived From: + * Created On: 5th February 1992 + * Purpose: This module contains the function CreateVideoSection + * which creates and maps a section which is used to + * save and restore video hardware data. It can't be in + * nt_fulsc.c because files that include nt.h can't + * include windows.h as well. + * + * (c)Copyright Insignia Solutions Ltd., 1992. All rights reserved. + * + * 03-May-1994 Jonle + * videosection creation has been moved to consrv for security + * removed all dead code associated with section maintenance + * + * ========================================================================== + */ + + + +IMPORT int DisplayErrorTerm(int, DWORD, char *, int); + +/*************************************************************************** + * Function: * + * LoseRegenMemory * + * * + * Description: * + * Lose the memory that will be remapped as vga regen. NOTE: need to * + * make this 'if fullscreen' only. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID LoseRegenMemory(VOID) +{ + int a = 0xa0000; + ULONG len = 0x20000; + NTSTATUS status; + + status = NtFreeVirtualMemory( + (HANDLE)GetCurrentProcess(), + (PVOID *)&a, + &len, + MEM_RELEASE); + if (!NT_SUCCESS(status)) + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); +} + + +/*************************************************************************** + * Function: * + * RegainRegenMemory * + * * + * Description: * + * When we switch back from fullscreen to windowed, the real regen * + * memory is removed and we are left with a gap. We have to put some * + * memory back into that gap before continuing windowed. * + * * + * Parameters: * + * None. * + * * + * Return value: * + * VOID * + * * + ***************************************************************************/ +GLOBAL VOID RegainRegenMemory(VOID) +{ + int regen = 0xa0000; + ULONG len = 0x20000; + HANDLE processHandle; + NTSTATUS status; + + if (!(processHandle = NtCurrentProcess())) + DisplayErrorTerm(EHS_FUNC_FAILED,(DWORD)processHandle,__FILE__,__LINE__); + + status = NtAllocateVirtualMemory( + processHandle, + (PVOID *) ®en, + 0, + &len, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if (! NT_SUCCESS(status) ) + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); +} + + +#ifdef X86GFX + +extern RTL_CRITICAL_SECTION IcaLock; +extern HANDLE hWowIdleEvent; + + +/***************************************************************************** + * Function: * + * GetROMsMapped * + * * + * Description: * + * Calls NT to get the ROMS of the host machine mapped into place in * + * emulated memory. The bottom page (4k) of PC memory is copied into * + * the bottom of emulated memory to provide the correct IVT & bios data * + * area setup for the mapped bios. (Which will have been initialised). * + * * + * Parameters: * + * None * + * * + * Return Value: * + * None - fails internally on NT error. * + * * + *****************************************************************************/ +GLOBAL VOID GetROMsMapped(VOID) +{ + NTSTATUS status; + VDMICAUSERDATA IcaUserData; + + IcaUserData.pIcaLock = &IcaLock; + IcaUserData.pIcaMaster = &VirtualIca[0]; + IcaUserData.pIcaSlave = &VirtualIca[1]; + IcaUserData.pDelayIrq = &DelayIrqLine; + IcaUserData.pUndelayIrq = &UndelayIrqLine; + IcaUserData.pDelayIret = &iretHookActive; + IcaUserData.pIretHooked = &iretHookMask; + IcaUserData.pAddrIretBopTable = &AddrIretBopTable; + IcaUserData.phWowIdleEvent = &hWowIdleEvent; + + status = NtVdmControl(VdmInitialize, &IcaUserData); + if (!NT_SUCCESS(status)) + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + +} +#endif //X86GFX diff --git a/private/mvdm/softpc.new/host/src/nt_smenu.c b/private/mvdm/softpc.new/host/src/nt_smenu.c new file mode 100644 index 000000000..5d51268ad --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_smenu.c @@ -0,0 +1,87 @@ +#include <windows.h> +#include <conapi.h> +#include "insignia.h" +#include "xt.h" +#include <stdio.h> +#include <stdlib.h> +#include <process.h> +#include "nt_graph.h" +#include "nt_smenu.h" + +/*================================================================ +Shared data. +================================================================*/ +BOOL bKillFlag = FALSE; /* shared with nt_input so the application can be */ + /* terminated in the input thread */ + +/*================================================================ +Function prototypes. +================================================================*/ + +void nt_settings_menu(); +BOOL FAR PASCAL DosDlgProc(HWND hDlg,WORD mess,LONG wParam,LONG lParam); + +/*================================================================ +Global data for this file only. +================================================================*/ + +static HANDLE InstHandle; + +/*================================================================ +The code starts here. +================================================================*/ + +void nt_settings_menu() +{ +InstHandle=GetModuleHandle(NULL); +if(DialogBox(InstHandle,"DosBox",NULL,(FARPROC)DosDlgProc) == -1) + DbgPrint("DialogBox() failed\n"); +} + +BOOL FAR PASCAL DosDlgProc(HWND hDlg,WORD mess,LONG wParam,LONG lParam) +{ +int nItem; + +switch(mess) + { + case WM_INITDIALOG: + return TRUE; + case WM_COMMAND: + { + switch(wParam) + { + case IDD_TERMINATE: + { + EndDialog(hDlg,0); + nItem=MessageBox(hDlg,"WARNING!!!!\n" + "Termination is a last resort. You\n" + "should end applications by using the\n" + "application's quit or exit command", + "Termination", + MB_OKCANCEL | MB_ICONSTOP | + MB_DEFBUTTON2 | MB_SYSTEMMODAL); + if(nItem==IDOK) + { + DbgPrint("Close down the application\n"); + bKillFlag = TRUE; + } + } + break; + case IDD_DGBOX: + { + } + break; + case IDD_FULLSCREEN: + { + } + break; + case IDOK: + case IDCANCEL: + EndDialog(hDlg,0); + } + return TRUE; + } + break; + } +return FALSE; +} diff --git a/private/mvdm/softpc.new/host/src/nt_sound.c b/private/mvdm/softpc.new/host/src/nt_sound.c new file mode 100644 index 000000000..10cc043ef --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_sound.c @@ -0,0 +1,420 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntddbeep.h> +#include <windows.h> +#include "insignia.h" +#include "host_def.h" +/* + * VPC-XT Revision 2.0 + * + * Title : sg_sound.c + * + * Description : This module provides functions to control sound. The + * functions are defined: + * + * host_ring_bell(duration) + * host_alarm(duration) + * host_timer2_waveform(delay,lowclocks,hiclocks,lohi,repeat) + * host_enable_timer2_sound() + * host_disable_timer2_sound() + * + * Author : + * + * Notes : + */ + +#include "xt.h" +#include "config.h" +#include "debug.h" +#include "error.h" +#include <stdio.h> +#include "trace.h" +#include "video.h" +#include "debug.h" + + +IMPORT ULONG GetPerfCounter(VOID); + +ULONG FreqT2 = 0; +BOOL PpiState = FALSE; +BOOL T2State = FALSE; +ULONG LastPpi = 0; +ULONG FreqPpi = 0; +ULONG ET2TicCount=0; +ULONG PpiCounting = 0; + +HANDLE hBeepDevice = 0; +ULONG BeepCloseCount = 0; +ULONG BeepLastFreq = 0; +ULONG BeepLastDuration = 0; + + +// human frequency audible sound range +#define AUDIBLE_MIN 10 +#define AUDIBLE_MAX 20000 +#define CLICK 100 + +VOID LazyBeep(ULONG Freq, ULONG Duration); +void PulsePpi(void); + +/*============================================================================ + + host_alarm - ring bell irrespective of configuration (used on keyboard + buffer overflow for example). + +=============================================================================*/ + +void host_alarm(duration) +long int duration; +{ +MessageBeep(MB_OK); +} + +/*======================================================================== + + host_ring_bell - ring bell if configured (used by video on output + of ^G, for example). + +=========================================================================*/ + +void host_ring_bell(duration) +long int duration; +{ +if( host_runtime_inquire(C_SOUND_ON)) + { + host_alarm(duration); + } +} + + + /* assumes caller holds ica lock */ + +VOID InitSound( BOOL bInit) +{ + if (!bInit) { + host_ica_lock(); + LazyBeep(0L, 0L); + if (hBeepDevice && hBeepDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hBeepDevice); + hBeepDevice = 0; + } + host_ica_unlock(); + return; + } +} + + +HANDLE OpenBeepDevice(void) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING NameString; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + HANDLE hBeep; + + RtlInitUnicodeString( &NameString, DD_BEEP_DEVICE_NAME_U ); + InitializeObjectAttributes( &ObjectAttributes, + &NameString, + 0, + NULL, + NULL + ); + + Status = NtCreateFile( &hBeep, + FILE_READ_DATA | FILE_WRITE_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN_IF, + 0, + (PVOID) NULL, + 0 + ); + + if (!NT_SUCCESS( Status )) { +#ifndef PROD + printf("NTVDM: OpenBeepDevice Status=%lx\n",Status); +#endif + hBeep = INVALID_HANDLE_VALUE; + } + + + return hBeep; +} + + + + +/* + * LazyBeep - + * Calls Beep Device Driver asynchronously + * + * Acceptable parameters are: + * (Freq,Dur) Action + * (0,0) - stop sound + * (nonzero, INFINITE) - play a freq + * + * not multithreaded safe + * + */ +VOID LazyBeep(ULONG Freq, ULONG Duration) +{ + IO_STATUS_BLOCK IoStatus; + BEEP_SET_PARAMETERS bps; + + if (Freq != BeepLastFreq || Duration != BeepLastDuration) { + bps.Frequency = Freq; + bps.Duration = Duration; + + // + // If the duration is < 10 ms, then we assume sound is being + // off so remember the state as 0,0 so that we won't turn it + // off again. + // + if (Duration < 10) { + BeepLastFreq = 0; + BeepLastDuration = 0; + } + else { + BeepLastFreq = Freq; + BeepLastDuration = Duration; + } + + if (!hBeepDevice) { + hBeepDevice = OpenBeepDevice(); + } + + if (hBeepDevice == INVALID_HANDLE_VALUE) { + return; + } + + NtDeviceIoControlFile( hBeepDevice, + NULL, + NULL, + NULL, + &IoStatus, + IOCTL_BEEP_SET, + &bps, + sizeof(bps), + NULL, + 0 + ); + + BeepCloseCount = 1000; + + } + + +} + + + + + +/* + * PlaySound + */ +void PlaySound(BOOL bPulsedPpi) +{ + if (PpiState && T2State && FreqT2) { + LazyBeep(FreqT2, INFINITE); + } + else if (FreqPpi > AUDIBLE_MIN) { + LazyBeep(FreqPpi,INFINITE); + } + else if (bPulsedPpi && PpiCounting) { + LazyBeep(CLICK,1); + } + else { + LazyBeep(0,0); + } +} + + + + +/* + * host_timer2_waveform - output specified sound waveform + * assumes caller holds ica lock (see base\timer.c) + */ +void host_timer2_waveform(int delay, + ULONG loclocks, + ULONG hiclocks, + int lohi, + int repeat) +{ + ULONG ul; + + if (loclocks == INFINITE || hiclocks == INFINITE) { + FreqT2 = 0; + } + else { + ul = loclocks + hiclocks; + if (!ul) + ul++; + FreqT2 = 1193180/ul; + + if (FreqT2 >= AUDIBLE_MAX) { + hiclocks = INFINITE; + FreqT2 = 0; + } + else if (FreqT2 <= AUDIBLE_MIN) { + loclocks = INFINITE; + FreqT2 = 0; + } + } + + PlaySound(FALSE); +} + + + +/* + * Updates the hosts Ppi sound state + */ +void HostPpiState(BYTE PortValue) +{ + BOOL bPpi; + + host_ica_lock(); + + T2State = PortValue & 1 ? TRUE: FALSE; + bPpi = PortValue & 2 ? TRUE: FALSE; + + if (bPpi != PpiState) { + PpiState = bPpi; + if (PpiState) { + PulsePpi(); + } + + PlaySound(PpiState); + } + + host_ica_unlock(); +} + + + + +void PulsePpi(void) +{ + static ULONG PpiTicStart=0; + static ULONG PpiCycles =0; + ULONG ul,Elapsed; + ULONG PrevTicCount; + + + PrevTicCount = ET2TicCount; + ET2TicCount = GetTickCount(); + Elapsed = ET2TicCount > PrevTicCount + ? ET2TicCount - PrevTicCount + : 0xFFFFFFFF - ET2TicCount + PrevTicCount; + + if (Elapsed > 200) { + if (PpiCounting) { + PpiCounting = 0; + LastPpi = 0; + FreqPpi = 0; + } + return; + } + + + if (!PpiCounting) { + PpiCounting = GetPerfCounter(); + PpiCycles = 0; + LastPpi = 0; + FreqPpi = 0; + PpiTicStart = ET2TicCount; + return; + } + + if (PpiTicStart + 200 >= ET2TicCount) { + PpiCycles++; + return; + } + + + ul = GetPerfCounter(); + Elapsed = ul >= PpiCounting + ? ul - PpiCounting + : 0xFFFFFFFF - PpiCounting + ul; + if (!Elapsed) // insurance! + Elapsed++; + PpiCounting = ul; + PpiTicStart = ET2TicCount; + + /* + * Calculate the new avergae Ppi, rounding off to keep + * signal from wavering. + */ + ul = (10000 * PpiCycles)/Elapsed; + if ((ul & 0x0f) > 7) + ul += 0x10; + ul &= ~0x0f; + ul += 0x10; // fudge factor + + if (!LastPpi) + LastPpi = ul; + if (!FreqPpi) + FreqPpi = LastPpi; + + /* + * New Average Ppi is derived from previous AveragePpi, + * plus last Ppi sample count plus current Ppi sample + * count to get a frequency which has minimal variation + * and at the same time responsive to change in the + * apps pulse rate. + */ + FreqPpi = ((FreqPpi << 2) + LastPpi + ul)/6; + if ((FreqPpi & 0x0f) > 7) + FreqPpi += 0x10; + FreqPpi &= ~0x0f; + + LastPpi = ul; + PpiCycles = 0; + +} + + + +/*============================================================ + +Function: PlayContinuousTone() +Called by: The SoftPC timer. + +==============================================================*/ + +void PlayContinuousTone(void) +{ + ULONG Elapsed; + + host_ica_lock(); + + if (PpiCounting) { + Elapsed = GetTickCount(); + Elapsed = Elapsed > ET2TicCount ? Elapsed - ET2TicCount + : 0xFFFFFFFF - ET2TicCount + Elapsed; + if (Elapsed > 200) { + PpiCounting = 0; + LastPpi = 0; + FreqPpi = 0; + } + } + + PlaySound(FALSE); + + if (!BeepLastFreq && !BeepLastDuration && + BeepCloseCount && !--BeepCloseCount) + { + if (hBeepDevice && hBeepDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hBeepDevice); + hBeepDevice = 0; + } + } + + host_ica_unlock(); +} diff --git a/private/mvdm/softpc.new/host/src/nt_term.c b/private/mvdm/softpc.new/host/src/nt_term.c new file mode 100644 index 000000000..6a36e8147 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_term.c @@ -0,0 +1,81 @@ +#include <windows.h> +#include <vdmapi.h> +#include "host_def.h" +#include "insignia.h" + +/* + * ========================================================================== + * Name: nt_term.c + * Author: Simon Frost + * Derived From: + * Created On: 7th May 1992 + * Purpose: This code moved from stubs.c and split to support + * the tidy up code and the actual exit code. + * + * (c)Copyright Insignia Solutions Ltd., 1992. All rights reserved. + * ========================================================================== + */ + +#include <conapi.h> +#include "xt.h" +#include "nt_graph.h" +#ifdef HUNTER +#include "nt_hunt.h" +#endif /* HUNTER */ +#include "ntcheese.h" + + +IMPORT VOID DeleteConfigFiles(VOID); // from command.lib + +/*::::::::::::::::::::::::::::::::::::::::: Do host cleanup before exiting */ +/*:::::::::::::::: Also called from reset() if VDM 'rebooted' */ + +void host_term_cleanup() +{ + GfxCloseDown(); // ensure video section destroyed +#ifdef X86GFX + if (sc.ScreenBufHandle) //dont want to leave console in graphics mode + CloseHandle(sc.ScreenBufHandle); +#endif // X86GFX + + /*:::::::::::::::::::::::::::::::::: Close open printer and comms ports */ + + host_lpt_close_all(); /* Close all open printer ports */ + host_com_close_all(); /* Close all open comms ports */ + MouseDetachMenuItem(TRUE); /* Force the menu item away on quit */ + + DeleteConfigFiles(); // make sure temp config files are deleted + +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::: Closedown the VDM */ +void host_terminate() +{ + + host_term_cleanup(); +#ifdef HUNTER + if (TrapperDump != (HANDLE) -1) + CloseHandle(TrapperDump); +#endif /* HUNTER */ + + if(VDMForWOW) + ExitVDM(VDMForWOW,(ULONG)-1); // Kill everything for WOW VDM + else + ExitVDM(FALSE,0); + + ExitProcess(0); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Terminate VDM */ + +VOID TerminateVDM(void) +{ + + /* + * Do base sepcific cleanup thru terminate(). + * NOTE: terminate will call host_terminate to do host + * specific cleanup + */ + + terminate(); +} diff --git a/private/mvdm/softpc.new/host/src/nt_thred.c b/private/mvdm/softpc.new/host/src/nt_thred.c new file mode 100644 index 000000000..c50740952 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_thred.c @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + nt_thred.c + +Abstract: + + Contains entry points for thread creation and destruction. These + entry points only need to be used for threads that will execute in + application mode. + +Author: + + Dave Hastings (daveh) 17-Apr-1992 + +Revision History: + +--*/ + +#include <windows.h> +#include <excpt.h> +#include <stdlib.h> +#include "nt_timer.h" +#include "monregs.h" + +typedef struct _ThreadStartUpParameters { + LPTHREAD_START_ROUTINE lpStartAddress; + LPVOID lpParameter; +} THREADSTARTUPPARAMETERS, *PTHREADSTARTUPPARAMETERS; + +DWORD ThreadStartupRoutine(PVOID pv); + + +HANDLE +WINAPI +host_CreateThread( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId + ) +/*++ + +Routine Description: + + This routine creates a thread that will later be used to execute + 16 bit application instructions. The parameters and end results + are the same as the Win 32 CreateThread function. This function + allows the IEU to take appropriate action on thread creation. + +Arguments: + + lpThreadAttributes -- Supplies the security attributes for the thread + dwStackSize -- Supplies the size fo the threads stack + lpStartAddress -- Supplies the starting address for the thread + lpParameter -- Supplies a parameter to the thread + dwCreationFlags -- Supplies flags that control the creation of the thread + lpThreadId -- Returns the Id of the thread + +Return Value: + + A handle to the thread if successful, + 0 otherwise. + +--*/ +{ + HANDLE Thread; + PTHREADSTARTUPPARAMETERS ptsp; + + ptsp = (PTHREADSTARTUPPARAMETERS) malloc(sizeof(THREADSTARTUPPARAMETERS)); + if (!ptsp) { + return 0; + } + + ptsp->lpStartAddress = lpStartAddress; + ptsp->lpParameter = lpParameter; + + Thread = CreateThread( + lpThreadAttributes, + dwStackSize, + ThreadStartupRoutine, + ptsp, + CREATE_SUSPENDED, + lpThreadId + ); + + if (Thread) { +/****************************** STF ********************************/ +#if defined(CCPU) || defined(PIG) + ccpu386newthread(); +#endif +/****************************** STF ********************************/ +#ifdef MONITOR + cpu_createthread(Thread); +#endif + if (!(dwCreationFlags & CREATE_SUSPENDED)) + ResumeThread(Thread); + + } else { + free(ptsp); + } + + return Thread; +} + + +DWORD ThreadStartupRoutine(PVOID pv) +{ + PTHREADSTARTUPPARAMETERS ptsp=pv; + THREADSTARTUPPARAMETERS tsp; + DWORD dwRet = (DWORD)-1; + + try { + tsp = *ptsp; + free(ptsp); + dwRet = tsp.lpStartAddress(tsp.lpParameter); + } except(VdmUnhandledExceptionFilter(GetExceptionInformation())) { + ; // we shouldn't arrive here + } + + return dwRet; +} + + +VOID +WINAPI +host_ExitThread( + DWORD dwExitCode + ) +/*++ + +Routine Description: + + This routine exits a thread. It allows the IEU to take appropriate + acction on thread terminiation. This routine only needs to be called + for threads have been created with host_CreateThread + +Arguments: + + dwExitCode -- Supplies the exit code for the thread. + +Return Value: + + None. + +--*/ +{ +/****************************** STF ********************************/ +#if defined(CCPU) || defined(PIG) + ccpu386exitthread(); +#endif +/****************************** STF ********************************/ +#ifdef MONITOR + cpu_exitthread(); +#endif + ExitThread(dwExitCode); +} diff --git a/private/mvdm/softpc.new/host/src/nt_timer.c b/private/mvdm/softpc.new/host/src/nt_timer.c new file mode 100644 index 000000000..bb4c75043 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_timer.c @@ -0,0 +1,982 @@ +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST + NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD. + +DOCUMENT : + +RELATED DOCS : + +DESIGNER : Dave Bartlett + +REVISION HISTORY : +First version : 20 May 1991 Dave Bartlett + +SUBMODULE NAME : nt_timer + +SOURCE FILE NAME : nt_timer.c + +PURPOSE : To provide the source of timing information + for the Win32 SoftPC, so that actions which + need to be taken at regular intervals may be + correctly scheduled. +*/ + + +/* +[1.INTERMODULE INTERFACE SPECIFICATION] + +[1.0 INCLUDE FILE NEEDED TO ACCESS THIS INTERFACE FROM OTHER SUBMODULES] + + INCLUDE FILE : nt_time.h + +[1.1 INTERMODULE EXPORTS] + + PROCEDURES() : int nt_timer_init() + int nt_timer_setup() + int nt_timer_shutdown() + int nt_timer_event() + +------------------------------------------------------------------------- +[1.2 DATATYPES FOR [1.1] + + STRUCTURES/TYPEDEFS/ENUMS: + +------------------------------------------------------------------------- +[1.3 INTERMODULE IMPORTS] + + PROCEDURES() : do_key_repeats() (module keyboard) + +------------------------------------------------------------------------- +========================================================================= +PROCEDURE : int nt_timer_init() + +PURPOSE : To initialise the host timing subsystem + +PARAMETERS : none + +GLOBALS : none + +RETURNED VALUE : 0 => failure + : ~0 => success + +DESCRIPTION : This function initialises the timing subsystem + +ERROR INDICATIONS : return value + +ERROR RECOVERY : Timing subsystem has not been initialised +========================================================================= +PROCEDURE : int nt_timer_setup() + +PURPOSE : To start the host timing subsystem + +PARAMETERS : none + +GLOBALS : none + +RETURNED VALUE : 0 => failure + : ~0 => success + +DESCRIPTION : This function starts the timing subsystem + +ERROR INDICATIONS : return value + +ERROR RECOVERY : Timing subsystem has not been started +========================================================================= +PROCEDURE : int nt_timer_shutdown() + +PURPOSE : To stop the host timing subsystem + +PARAMETERS : none + +GLOBALS : none + +RETURNED VALUE : 0 => failure + : ~0 => success + +DESCRIPTION : This function stops the timing subsystem + +ERROR INDICATIONS : return value + +ERROR RECOVERY : Timing subsystem has not been stopped +========================================================================= +PROCEDURE : int nt_timer_event() + +PURPOSE : To indicate to the timing subsystem that a timer + event may now take place, and to cause any time-based + activities to occur. + +PARAMETERS : none + +GLOBALS : none + +DESCRIPTION : All functions implementing time-based functions + are called if their turn has arrived. + +ERROR INDICATIONS : none + +ERROR RECOVERY : errors are ignored +/*======================================================================= +[3.INTERMODULE INTERFACE DECLARATIONS] +========================================================================*/ + +/* [3.1 INTERMODULE IMPORTS] */ + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files*/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "insignia.h" +#include "host_def.h" + +#include <stdio.h> +#include <sys/types.h> +#include <signal.h> +#include <time.h> +#include <excpt.h> + +#include "xt.h" +#include CpuH +#include "bios.h" +#include "sas.h" +#include "timer.h" +#include "tmstrobe.h" +#include "gmi.h" +#include "gfx_upd.h" +#include "timeval.h" +#include "timestmp.h" +#include "host_rrr.h" +#include "error.h" +#include "quick_ev.h" +#include "nt_timer.h" +#include "nt_uis.h" +#include "idetect.h" + +#include "debug.h" +#ifndef PROD +#include "trace.h" +#include "host_trc.h" +#endif + +#include "ica.h" +#include "nt_uis.h" +#include "nt_thred.h" +#include "nt_com.h" +#include <ntddvdeo.h> +#include "conapi.h" +#include "nt_fulsc.h" +#include "nt_graph.h" +#include "nt_det.h" +#include "nt_reset.h" +#include "nt_pif.h" +#include "nt_eoi.h" +#include "nt_event.h" + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::: INTERMODULE EXPORTS */ + +IMPORT void ReinitIdealTime(struct host_timeval *); +THREAD_DATA ThreadInfo; +CRITICAL_SECTION TimerTickCS; +CRITICAL_SECTION HBSuspendCS; + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::: Local Declarations */ + +DWORD Win32_host_timer(void); +NTSTATUS DelayHeartBeat(LONG Delay); +VOID host_init_bda_timer(void); +GLOBAL void rtc_init IFN0(); +VOID InitPerfCounter(VOID); +DWORD HeartBeatThread(PVOID pv); +void CreepAdjust(LARGE_INTEGER DiffTime); +void DemHeartBeat(void); + +#ifndef MONITOR +void quick_tick_recalibrate(void); +#endif + +void rtc_init(void); +void RtcTick(struct host_timeval *time); + +/*::::::::::::::::::::::::::::::::::::::::::::::: INTERNAL DATA DEFINITIONS */ + +// +// Perfcounter frequency calculation constants +// +ULONG ulFreqHusec; +ULONG ulFreqSec; + + +// +// Events for resuming\suspending heartbeat +// +HANDLE hHBResumeEvent; +HANDLE hHBSuspendEvent; + +// +// HeartBeat TimeStamps in usec +// +LARGE_INTEGER CurrHeartBeat; +LARGE_INTEGER TimerEventUSec; +LARGE_INTEGER CumUSec; +LARGE_INTEGER CreepUSec; +LARGE_INTEGER CreepTicCount; + +int HeartBeatResumes=0; +BOOL bDoingTicInterrupt=FALSE; +BOOL bUpdateRtc; + + + + +#if defined (MONITOR) && defined (X86GFX) +HANDLE SuspendEventObjects[2]; +#endif + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: NT timer initialise ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void host_timer_init(void) +{ + + ThreadInfo.HeartBeat.Handle = CreateThread( + NULL, + 8192, + HeartBeatThread, + NULL, + CREATE_SUSPENDED, + &ThreadInfo.HeartBeat.ID + ); + + if(!ThreadInfo.HeartBeat.Handle) { + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + TerminateVDM(); + } + + InitSound(TRUE); + + return; +} + +/* + * TimerInit + * + * Some of the timerinit stuff was split off, because it needs to be + * done before any chance of calling vdm error popups. + * Until I understand why creating the heartbeat thread very early + * causes a console-ntvdm deadlock, the functions should remain split + * + */ +void TimerInit(void) +{ + + if(!(hHBResumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + TerminateVDM(); + } + + if(!(hHBSuspendEvent = CreateEvent(NULL, FALSE, TRUE, NULL))) { + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + TerminateVDM(); + } + + InitializeCriticalSection(&TimerTickCS); + InitializeCriticalSection(&HBSuspendCS); + + InitPerfCounter(); + +} + + +/* + * HeartBeat Termination + * + */ +void TerminateHeartBeat(void) +{ + NtAlertThread(ThreadInfo.HeartBeat.Handle); + if (ThreadInfo.HeartBeat.ID != GetCurrentThreadId()) + WaitForSingleObjectEx(ThreadInfo.HeartBeat.Handle, 10000, TRUE); + + return; +} + + +// +// Initialized by base, initialize frequencies for perf counter +// +VOID InitPerfCounter(VOID) +{ + LARGE_INTEGER li, liFreq; + + + NtQueryPerformanceCounter(&li, &liFreq); + /* we assumed the frequency never goes beyond 4Ghz(32bits) + * if it does someday, this assumption must be removed + * and code must be rewritten + */ + ASSERT(liFreq.HighPart == 0); + ulFreqSec = liFreq.LowPart; + ulFreqHusec = liFreq.LowPart / 10000; + +} + +// +// returns perf counter in 100's usecs (0.1 millisec) +// +// +ULONG GetPerfCounter(VOID) +{ + LARGE_INTEGER li; + + NtQueryPerformanceCounter(&li, NULL); + li = RtlExtendedLargeIntegerDivide(li, ulFreqHusec, NULL); + return(li.LowPart); +} + + + +// +// returns perf counter in usec +// +// +void GetPerfCounterUsecs(struct host_timeval *time, PLARGE_INTEGER pliTime) +{ + LARGE_INTEGER liSecs; + LARGE_INTEGER liUsecs; + + // get time in secs and usecs + NtQueryPerformanceCounter(&liSecs, NULL); + liSecs = RtlExtendedLargeIntegerDivide(liSecs, ulFreqSec, &liUsecs.LowPart); + liUsecs.QuadPart = Int32x32To64(liUsecs.LowPart, 1000000); + liUsecs = RtlExtendedLargeIntegerDivide(liUsecs, ulFreqSec, NULL); + + // fill in time if specified + if (time) { + time->tv_usec = liUsecs.LowPart; + time->tv_sec = liSecs.LowPart; + } + + // fill in pliTime if specified + if (pliTime) { + pliTime->QuadPart = liUsecs.QuadPart + liSecs.QuadPart * 1000000; + } + return; +} + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::: Timer Event Code :::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::;::::::::::::::::*/ +void host_timer_event() +{ + + if (!VDMForWOW) { + unsigned char FgBgPriority; + +#ifdef X86GFX + /* Don't do timer tick while in fullscreen switch code. */ + if (NoTicks) + return; + + /* Do console calls related to fullscreen switching. */ + CheckForFullscreenSwitch(); + +#endif /* X86GFX */ + + host_graphics_tick(); // video graphics stuff + + +#ifndef X86GFX + /* Are there any screen scale events to process. */ + GetScaleEvent(); +#endif + + IDLE_tick(); // IDLE accounting + + /* + * We can't detect idling on all apps (eg Multiplan). For these apps + * a PIF setting for 'Foreground Priority' of < 100% is recomended. + * Where this happens, we idle for the 'unwanted' portion of a tick + * period. + */ + FgBgPriority = sc.Focus ? WNTPifFgPr : WNTPifBgPr; + if (FgBgPriority < 100) + PrioWaitIfIdle(FgBgPriority); + } + +#ifndef MONITOR + quick_tick_recalibrate(); +#endif + + + +#ifdef YODA + CheckForYodaEvents(); +#endif + + host_com_heart_beat(); // com device + + host_lpt_heart_beat(); // printer devuce + + host_flpy_heart_beat(); // direct floppy device + + DemHeartBeat(); + + time_strobe(); // time/date etc. (NOT time ticks) + + PlayContinuousTone(); // sound emulation + +} + + +/* + * Called to set up the Bios Data area time update vars. + * and the heart beat's counters + */ +VOID host_init_bda_timer(void) +{ + SYSTEMTIME TimeDate; + ULONG Ticks; + struct host_timeval time; + + + CreepTicCount.QuadPart = NtGetTickCount(); + GetPerfCounterUsecs(&time, &CumUSec); + GetLocalTime(&TimeDate); + + Ticks = (ULONG)TimeDate.wHour * 65543 + + (ULONG)TimeDate.wMinute * 1092 + + (ULONG)TimeDate.wSecond * 18 ; + + if (TimeDate.wHour) + Ticks += (ULONG)TimeDate.wHour/3; + if (TimeDate.wMinute) + Ticks += (ULONG)(TimeDate.wMinute*4)/10; + if (TimeDate.wSecond) + Ticks += (ULONG)TimeDate.wSecond/5; + if (TimeDate.wMilliseconds) + Ticks += ((ULONG)TimeDate.wMilliseconds)/54; + + Ticks++; // fudge factor! + + CreepUSec = CumUSec; + TimerEventUSec.QuadPart = CumUSec.QuadPart + SYSTEM_TICK_INTV; + ReinitIdealTime(&time); + + + /* + * BUGBUG with sas strange errors when writing from non cpu thread + * + * sas_storew(TIMER_LOW, BDA & 0xffff); + * sas_storew(TIMER_HIGH, (BDA >> 16) & 0xffff); + * sas_store(TIMER_OVFL, 0x01); + */ + * (word *)(Start_of_M_area + TIMER_HIGH) = (word)(Ticks >> 16); + * (word *)(Start_of_M_area + TIMER_LOW) = (word)Ticks; + * (half_word *)(Start_of_M_area + TIMER_OVFL) = (half_word)0; + + + // reset the Real Time Clock + rtc_init(); + +#ifndef MONITOR + q_event_init(); +#endif + +} + + + +/* host_GetSysTime, replacement for the base function + * + * + * This routine does not return the system's time of day. + * Uses the NT performance counter to obtain time stamping + * information for the base to use. The resolution is microsecs. + * + * Returns nothing, fills in time structure + * + */ +void host_GetSysTime(struct host_timeval *time) +{ + LARGE_INTEGER liTime; + + // Don't call kernel unless we have to. + if (bDoingTicInterrupt) { + liTime = RtlExtendedLargeIntegerDivide( + CurrHeartBeat, + 1000000, + &time->tv_usec); + time->tv_sec = liTime.LowPart; + } + else { + GetPerfCounterUsecs(time, NULL); + } +} + + +/* host_TimeStamp + * + * This routine does not return the system's time of day. + * Uses the NT performance counter to obtain time stamping + * information for the base to use. Returns LARGE_INTEGER + * with time since boot in usecs. + * + */ +void host_TimeStamp(PLARGE_INTEGER pliTime) +{ + host_ica_lock(); + + if (bDoingTicInterrupt) { + *pliTime = CurrHeartBeat; + } + else { + GetPerfCounterUsecs(NULL, pliTime); + } + + host_ica_unlock(); +} + + + + + + + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::: Win32 timer function entry point :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +DWORD HeartBeatThread(PVOID pv) +{ + DWORD dwRet = (DWORD)-1; + + try { + +#ifdef MONITOR + // + // On x86 we have to force the creation of the critsect lock semaphore + // When the heartbeat thread start running the cpu thread holds the + // ica lock forcing contention (and creation). See ConsoleInit. + // + host_ica_lock(); // take ica lock to force creation of critsect +#endif + + + // + // Set our priority above normal, and wait for signal to + // start heartbeat pulses. + // + // For Wow we raise to time critical because wow apps can + // easily invoke a tight client-csr-server bound loop with + // boosted priority starving the heartbeat thread. Winbench 311 + // shows this problem when doing polylines test. + // + SetThreadPriority(ThreadInfo.HeartBeat.Handle, + !(dwWNTPifFlags & COMPAT_TIMERTIC) + ? THREAD_PRIORITY_TIME_CRITICAL + : THREAD_PRIORITY_HIGHEST + ); + +#ifdef X86GFX + SuspendEventObjects[0] = hHBSuspendEvent; + + /* Get the switching event handle. */ + if (!VDMForWOW) { + SuspendEventObjects[1] = GetDetectEvent(); + } + else { + SuspendEventObjects[1] = INVALID_HANDLE_VALUE; + } +#endif + +#ifdef MONITOR + host_ica_unlock(); +#endif + + dwRet = Win32_host_timer(); + + } + except(VdmUnhandledExceptionFilter(GetExceptionInformation())) { + ; // we shouldn't arrive here + } + + return dwRet; +} + + +#ifdef PIG +int TimerCount = 20; +#endif /* PIG */ + +DWORD Win32_host_timer(void) +{ + NTSTATUS status; +#ifdef PIG + int count = 0; +#endif /* PIG */ + LONG DelayPeriod; + LARGE_INTEGER DiffTime; + LARGE_INTEGER SystemTickIntv; + LARGE_INTEGER SecIntv; + LARGE_INTEGER HalfSysIntv; + LARGE_INTEGER CreepIntv; + + + struct host_timeval time; + + DelayPeriod = 50000; + SystemTickIntv.QuadPart = SYSTEM_TICK_INTV; + HalfSysIntv.QuadPart = SYSTEM_TICK_INTV/2; + SecIntv.QuadPart = SYSTEM_TICK_INTV*18; + CreepIntv.QuadPart = Int32x32To64(SYSTEM_TICK_INTV, 1200); // >1 hr + + + /* Start timing loop. */ + while(1) { + status = DelayHeartBeat(DelayPeriod); + if (!status) { // reinitialize counters +HBresume: + host_ica_lock(); + host_init_bda_timer(); + DelayPeriod = SYSTEM_TICK_INTV - 6000; + host_ica_unlock(); + continue; + } + + host_ica_lock(); + bDoingTicInterrupt = TRUE; + /* + * Get the current perf counter time, We ignore wrap + * since it only happens every few hundred years. + */ + GetPerfCounterUsecs(&time, &CurrHeartBeat); + + /* + * Increment the cumulative counter + */ + CumUSec.QuadPart = CumUSec.QuadPart + SYSTEM_TICK_INTV; + + /* + * if we have passed the creep interval, Adjust the cumulative + * counter for drift between perfcounter and tic counter. + */ + DiffTime.QuadPart = CurrHeartBeat.QuadPart - CreepUSec.QuadPart; + if (DiffTime.QuadPart > CreepIntv.QuadPart) { + CreepAdjust(DiffTime); + } + + /* + * Calculate Next Delay Period, based on how far + * behind we are. ie CurrTime - CumTime. + */ + DiffTime.QuadPart = CurrHeartBeat.QuadPart - CumUSec.QuadPart; + + if (DiffTime.QuadPart > SecIntv.QuadPart) + { + DelayPeriod = 13000; + } + else if (DiffTime.QuadPart > SYSTEM_TICK_INTV) + { + DelayPeriod = SYSTEM_TICK_INTV/3; + } + else if (DiffTime.QuadPart >= HalfSysIntv.QuadPart) + { + DiffTime.QuadPart = (LONGLONG)SYSTEM_TICK_INTV - DiffTime.QuadPart; + DelayPeriod = DiffTime.LowPart - 6000; + } + else { + DelayPeriod = SYSTEM_TICK_INTV - 6000 - DiffTime.LowPart; + } + + + + /* + * Update the VirtualTimerHardware + */ +#ifdef PIG + if (++count >= TimerCount) + { + time_tick(); + count = 0; + } +#else + time_tick(); +#endif /* PIG */ + + + /* + * Update the Real Time Clock + */ + RtcTick(&time); + + bDoingTicInterrupt = FALSE; + host_ica_unlock(); + + + /* Timer Event should occur around 18 times per sec + * The count doesn't have to be all that accurate, so we + * don't try to make up for lost events, and we do this last + * to give a chance for hw interrupts to get thru first. + */ + if (TimerEventUSec.QuadPart <= CurrHeartBeat.QuadPart) { + TimerEventUSec.QuadPart = CurrHeartBeat.QuadPart + SYSTEM_TICK_INTV; + cpu_interrupt(CPU_TIMER_TICK, 0); + WOWIdle(TRUE); + } + } + + return(1); +} + + +/* + * DelayHeartBeat + * + * waits the Delay as required by caller + * while also checking for the following: + * - suspend\resume events + * - screen switching event (x86 graphics) + * + * entry : delay time in micro secs + * exit : TRUE - reinit counters + */ + +NTSTATUS DelayHeartBeat(LONG Delay) +{ + NTSTATUS status; + LARGE_INTEGER liDelay; + + + liDelay.QuadPart = Int32x32To64(Delay, -10); + +#ifdef MONITOR + +RewaitSuspend: + status = NtWaitForMultipleObjects(VDMForWOW ? 1 : 2, + SuspendEventObjects, + WaitAny, + TRUE, + &liDelay); + + // delay time has expired + if (status == STATUS_TIMEOUT) { + return status; + } + +#ifdef X86GFX // screen switch event + if (status == 1) { + DoHandShake(); + liDelay.QuadPart = -10; + goto RewaitSuspend; + } +#endif + + // suspend event + if (!status) { + SuspendEventObjects[0] = hHBResumeEvent; + ica_hw_interrupt_cancel(ICA_MASTER,CPU_TIMER_INT); + host_DelayHwInterrupt(CPU_TIMER_INT, 0, 0xFFFFFFFF); + +RewaitResume: + status = NtWaitForMultipleObjects(VDMForWOW ? 1 : 2, + SuspendEventObjects, + WaitAny, + TRUE, + NULL); + + // resume event + if (!status) { + SuspendEventObjects[0] = hHBSuspendEvent; + return status; + } + + +#ifdef X86GFX // screen switch event + if (status == 1) { + DoHandShake(); + goto RewaitResume; + } +#endif + } + + +#else // ndef MONITOR +// +// On Risc platforms we only have to deal with the +// HeartBeat Resume\Suspend objects so things are much simpler +// + + status = NtWaitForSingleObject(hHBSuspendEvent, + TRUE, + &liDelay); + + if (status == STATUS_TIMEOUT) { + return status; + } + + if (status == STATUS_SUCCESS) { // suspend event + status = NtWaitForSingleObject(hHBResumeEvent, TRUE, NULL); + if (status == STATUS_SUCCESS) { + return status; + } + } + +#endif + + // alerted to die + if (status == STATUS_ALERTED) { + CloseHandle(ThreadInfo.HeartBeat.Handle); + ThreadInfo.HeartBeat.Handle = NULL; + ThreadInfo.HeartBeat.ID = 0; + ExitThread(0); + } + + + // Must be an error, announce it to the world + DisplayErrorTerm(EHS_FUNC_FAILED, status,__FILE__,__LINE__); + TerminateVDM(); + return status; +} + +/* + * CreepAdjust + * + * Adjusts the perfcounter cum time stamp for drift from system time of + * day (Kernel Tick Count) + */ +void CreepAdjust(LARGE_INTEGER DiffTime) +{ + LARGE_INTEGER DiffTicCount; + ULONG ulTicCount; + + // Calculate the elapsed ticcount in usecs + ulTicCount = NtGetTickCount(); + DiffTicCount.LowPart = ulTicCount; + DiffTicCount.HighPart = CreepTicCount.HighPart; + if (DiffTicCount.LowPart < CreepTicCount.LowPart) { + DiffTicCount.HighPart++; + } + DiffTicCount.QuadPart = DiffTicCount.QuadPart - CreepTicCount.QuadPart; + DiffTicCount = RtlExtendedIntegerMultiply(DiffTicCount, 1000); + + // Adjust the CumUsec perfcounter time by the diff + // between tick count and perfcounter. + DiffTicCount.QuadPart = DiffTicCount.QuadPart - DiffTime.QuadPart; + CumUSec.QuadPart = CumUSec.QuadPart - DiffTicCount.QuadPart; + + // Reset the Creep Time stamps + CreepTicCount.QuadPart = ulTicCount; + CreepUSec = CurrHeartBeat; +} + + +/* SuspendTimerThread\ResumeTimerThread + * + * functions to supsend\resume the heartbeat thread + * - used by ntvdm when dos apps exit + * - used by wow when only wowexec is running + * - used by wow for tasks requiring timer tics\BDA tic count updates + * + * These two functions keep an internal suspend counter, to manage + * wows multiple tasks, some which require tics, some don't. As long + * as one task requires tics\bda updates, we will deliver them for all + * tasks. + * + */ + + +/* SuspendTimerThread + * + * Blocks the timer thread on an event + * Increments internal suspend count + * + * This function will NOT wait until the heartbeat is safely blocked + * before returning. + * + * entry: void + * exit: void + * + */ +GLOBAL VOID SuspendTimerThread(VOID) +{ + RtlEnterCriticalSection(&HBSuspendCS); + + if (!--HeartBeatResumes) { + SetEvent(hHBSuspendEvent); + } + + RtlLeaveCriticalSection(&HBSuspendCS); +} + + + +/* ResumeTimerThread + * + * restarts the heart beat thread, by setting event + * decrements internal suspend count + * + * entry: void + * exit: void + * + */ +GLOBAL VOID ResumeTimerThread(VOID) +{ + RtlEnterCriticalSection(&HBSuspendCS); + + if (!HeartBeatResumes++) { + SetEvent(hHBResumeEvent); + } + + RtlLeaveCriticalSection(&HBSuspendCS); +} + + + +/* + * This function handles all of the toplevel + * exceptions for all ntvdm threads which are known. + * This includes the event thread, heartbeat thread, comms thread, + * and all application threads (those which use host_CreateThread()). + * + * Threads which are not covered are those created by unknown Vdds. + * + * If the UnHandleExecptionFilter api returns EXECEPTION_EXECUTE_HANDLER + * the process will be terminated and this routine will not return. + * + */ +LONG +VdmUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ) +{ + LONG lRet; + + SuspendTimerThread(); + + lRet = UnhandledExceptionFilter(ExceptionInfo); + + if (lRet == EXCEPTION_EXECUTE_HANDLER) { + NtTerminateProcess(NtCurrentProcess(), + ExceptionInfo->ExceptionRecord->ExceptionCode + ); + } + + ResumeTimerThread(); + return lRet; +} diff --git a/private/mvdm/softpc.new/host/src/nt_umb.c b/private/mvdm/softpc.new/host/src/nt_umb.c new file mode 100644 index 000000000..d6c9a4ffa --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_umb.c @@ -0,0 +1,1119 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + UMB.C + +Abstract: + + UMB management functions for NT MVDM + +Author: + + William Hsieh (williamh) Created 21-Sept-1992 + +[Environment:] + + User Mode, running in the context of MVDM + +[Notes:] + + optional-notes + +Revision History: + +--*/ +#include "nt.h" +#include "ntrtl.h" // for romdump +#include "nturtl.h" +#include "windows.h" +#include "host_def.h" +#include "insignia.h" +#include "stdlib.h" +#include "xt.h" +#include CpuH +#include "error.h" +#include "sas.h" +#include "ios.h" +#include "umb.h" + +#include <nt_vdd.h> +#include <nt_vddp.h> +#include <emm.h> + +PUMBNODE +SpliceUMB( +PUMBNODE UMB, +DWORD dwBase, +DWORD Size, +WORD Owner +); + +BOOL +VDDReserveUMB( +DWORD dwBase, +DWORD Size, +PUMBNODE UMB +); +VOID +xmsReleaseUMBNotify( +PVOID Address, +DWORD Size +); +PUMBNODE UMBList; + +HANDLE UMBSectionHandle; + +// This function allocate a address space from the UMB area. +// Depends on the requester, this function changes the given address +// space reservation/commitment and ownership states of the block. +// From the very beginning, InitUMBList reserves every possible UMB and +// each unused UMB has owner of UMB_OWNER_NONE or UMB_OWNER_ROM. +// An UMB_OWNER_NONE block is freed and can be claimed by anybody; +// An UMB_OWNER_ROM is mapped to system ROM area and nobody can +// claim it except UMB_OWNER_NONE which includes the ROM UMB as +// usual UMB so that its address space can be used for other purpose. +// This exception was added for VDDs(trusted requesters) only. +// An UMB_OWNER_RAM block is reserved and committed. Nobody can claim +// it except UMB_OWNER_XMS(and UMB_OWNER_XMS can only claim UMB_OWNER_RAM). +// An UMB_OWNER_EMM block is simply reserved. +// An UMB_OWNER_XMS block is reserved, committed and under XMS control. +// An UMB_OWNER_VDD block is claimed by a VDD via VDDInstallMemoryHook. +// VDD block got special treatment because memory are committed to and +// decommitted from within the block dynamycally, depends on how the +// VDD wants to manipulate it. +// +// WARNING: The given Size and Address must on system page boundary. +// +BOOL +ReserveUMB( +WORD Owner, +PVOID *Address, +DWORD *Size +) +{ + +#ifdef MONITOR + NTSTATUS Status; +#endif + + PUMBNODE UMB; + LARGE_INTEGER SectionOffset; + + DWORD dwBase; + + dwBase = (DWORD)*Address; + + // get the UMB list header + UMB = UMBList; + SectionOffset.HighPart = 0; + + switch (Owner) { + case UMB_OWNER_RAM: + // commit memory to every free UMB in the list + // this is the only case which works on multiple blocks + while (UMB != NULL) { + if (UMB->Owner == UMB_OWNER_NONE) { +#ifndef MONITOR + // Is this necessary? + sas_connect_memory(UMB->Base, UMB->Base + UMB->Size - 1, SAS_RAM); + +#else + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *)&UMB->Base, + 0, + &UMB->Size, + MEM_COMMIT, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } +#endif + UMB->Owner = UMB_OWNER_RAM; + } + UMB = UMB->Next; + } + break; + + case UMB_OWNER_EMM: + + while (UMB != NULL) { + if (UMB->Owner == UMB_OWNER_NONE && + UMB->Size >= *Size && + (dwBase == 0 || (dwBase >= UMB->Base && + (dwBase + *Size) <= UMB->Base + UMB->Size)) + ) + break; + UMB = UMB->Next; + } + if (UMB == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + if (dwBase == 0) + dwBase = UMB->Base; + + // the found block may be too big for the request + // we have to splice the block if that is the case + UMB = SpliceUMB(UMB, dwBase, *Size, UMB_OWNER_EMM); + // if failed to do something, simple fail + if (UMB == NULL) { + return FALSE; + } +#ifdef MONITOR + SectionOffset.HighPart = 0; + SectionOffset.LowPart = UMB->Base - UMB_BASE_ADDRESS; + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *) &UMB->Base, + 0, + 0, + &SectionOffset, + &UMB->Size, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } +#endif + // return the block address + *Address = (PVOID)UMB->Base; + break; + + case UMB_OWNER_XMS: + // search UMB_OWNER_RAM and claim the ownership + while (UMB != NULL && UMB->Owner != UMB_OWNER_RAM) { + UMB = UMB->Next; + } + if (UMB == NULL) { + // don't set last error here + return FALSE; + } + else { + UMB->Owner = UMB_OWNER_XMS; + *Address = (PVOID)UMB->Base; + *Size = UMB->Size; + } + break; + + case UMB_OWNER_VDD: + return(VDDReserveUMB(dwBase, *Size, UMB)); + +// VDDExcludeMem and VDDIncludeMem support cases + case UMB_OWNER_NONE: + //call to change a rom block to a free UMB block + //the given address and size must exactly match + +#ifndef MONITOR + // on MIPS, rom blocks are BIOS and VIDEO. No reason to change it + return FALSE; +#else + while(UMB != NULL && (UMB->Owner != UMB_OWNER_ROM || + UMB->Base != dwBase || + UMB->Size != *Size)) { + UMB = UMB->Next; + } + if (UMB == NULL) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + // unmap the rom first. Kernel map it into a unknown section + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)UMB->Base + ); + if (NT_SUCCESS(Status)) { + *Address = (PVOID)UMB->Base; + SectionOffset.LowPart = UMB->Base - UMB_BASE_ADDRESS; + *Size = UMB->Size; + // map the address into our section(reserved) + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + Address, + 0, + 0, + &SectionOffset, + Size, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + UMB->Owner = UMB_OWNER_NONE; + } + break; +#endif + + case UMB_OWNER_ROM: + // case to excluede a UMB + while (UMB != NULL && (UMB->Owner != UMB_OWNER_NONE || + UMB->Base > dwBase + *Size || + UMB->Base + UMB->Size < dwBase + *Size)) { + UMB = UMB->Next; + } + if (UMB == NULL) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + UMB = SpliceUMB(UMB, dwBase, *Size, UMB_OWNER_ROM); + if (UMB == NULL) { + return FALSE; + } +#ifdef MONITOR + + // reserve and commit the block + SectionOffset.LowPart = UMB->Base - UMB_BASE_ADDRESS; + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *)&UMB->Base, + 0, + UMB->Size, + &SectionOffset, + &UMB->Size, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } +#endif + UMB->Owner = UMB_OWNER_ROM; + break; + + + default: + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + return TRUE; +} + +// This function reclaims the given UMB. +// Note that every reclaimed UMB is set to UMB_OWNER_RAM, reserved and +// committed. After the call, the UMB can be claimed by XMS driver. +// A VDD will find that it can not reserve an UMB second time. This is +// because we have to put the address space into committed states so +// that we won't get access violation and crach VDM(remember we are +// simulating DOS machine, a machine where applications can do whatever +// they want). + +BOOL +ReleaseUMB( +WORD Owner, +PVOID Address, +DWORD Size +) +{ + +#ifdef MONITOR + USHORT Count; + NTSTATUS Status; +#endif + + PUMBNODE UMB; + LARGE_INTEGER SectionOffset; + DWORD SizeView, dwBase; + + + + dwBase = (DWORD)Address; + + UMB = UMBList; + // size, address and owner must match before releasing + while (UMB != NULL && (UMB->Owner != Owner || + dwBase != UMB->Base || + Size != UMB->Size)) { + UMB = UMB->Next; + } + if (UMB == NULL) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + SizeView = UMB->Size; + SectionOffset.HighPart = 0; + SectionOffset.LowPart = dwBase - UMB_BASE_ADDRESS; + + switch (Owner) { + case UMB_OWNER_EMM: +#ifndef MONITOR + sas_connect_memory(UMB->Base, UMB->Base + UMB->Size - 1, SAS_RAM); +#else + //commit the meory block + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *) &dwBase, + 0, + &SizeView, + MEM_COMMIT, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } +#endif + UMB->Owner = UMB_OWNER_RAM; + xmsReleaseUMBNotify((PVOID)UMB->Base, UMB->Size); + break; + + case UMB_OWNER_VDD: +#ifndef MONITOR + sas_connect_memory(dwBase, dwBase + Size - 1, SAS_RAM); +#else + Count = (USHORT)(SizeView / HOST_PAGE_SIZE); + SizeView = HOST_PAGE_SIZE; + // unmap every page + for (; Count > 0; Count--, dwBase += HOST_PAGE_SIZE) { + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)dwBase + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + SectionOffset.LowPart = UMB->Base - UMB_BASE_ADDRESS; + dwBase = UMB->Base; + SizeView = UMB->Size; + // reserve and commit the meory(the entire block) + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *) &dwBase, + 0, + SizeView, + &SectionOffset, + &SizeView, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } +#endif + UMB->Owner = UMB_OWNER_RAM; + xmsReleaseUMBNotify((PVOID)UMB->Base, UMB->Size); + break; + + default: + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + return TRUE; + +} +// This function commit memory to the specific address space +// for VDD. +BOOL +VDDCommitUMB( +PVOID Address, +DWORD Size +) +{ + +#ifdef MONITOR + NTSTATUS Status; + DWORD Mask, SizeView; + USHORT Count; + LARGE_INTEGER SectionOffset; +#endif + + PUMBNODE UMB; + DWORD dwBase; + + UMB = UMBList; + + dwBase = (DWORD)Address; + while(UMB != NULL && (UMB->Owner != UMB_OWNER_VDD || + UMB->Base + UMB->Size < dwBase + Size || + UMB->Base > dwBase + Size)) { + UMB = UMB->Next; + } + + if (UMB == NULL){ + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } +#ifndef MONITOR + sas_connect_memory(dwBase, dwBase + Size - 1, SAS_RAM); +#else + Mask = 1 << ((dwBase - UMB->Base) / HOST_PAGE_SIZE); + SizeView = HOST_PAGE_SIZE; + Count = (USHORT)(Size / HOST_PAGE_SIZE); + SectionOffset.HighPart = 0; + SectionOffset.LowPart = dwBase - UMB_BASE_ADDRESS; + + for (; Count > 0; Count--, Mask <<= 1) { + // Commit memory if didn't do this before + if ((UMB->Mask & Mask) == 0) { + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *)&dwBase, + 0, + &SizeView, + MEM_COMMIT, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + UMB->Mask |= Mask; + } + else { + // the section has memory for it, + // first unmap it and then map it with correct commit size + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)dwBase + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *)&dwBase, + 0, + HOST_PAGE_SIZE, + &SectionOffset, + &SizeView, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + } + SectionOffset.LowPart += HOST_PAGE_SIZE; + dwBase += HOST_PAGE_SIZE; + } +#endif + + return TRUE; +} +// This function decommit memory from the specific address space +// WARNING: We can never really decommit the memory. We just +// change the address space states from committed to reserve so +// that VDD will get page fault. +BOOL +VDDDeCommitUMB( +PVOID Address, +DWORD Size +) +{ +#ifdef MONITOR + NTSTATUS Status; + DWORD PageSize, PageMask; + USHORT PageCount; + LARGE_INTEGER SectionOffset; + +#endif + + PUMBNODE UMB; + DWORD dwBase; + + + + dwBase = (DWORD)Address; + UMB = UMBList; + while(UMB != NULL && (UMB->Owner != UMB_OWNER_VDD || + UMB->Base + UMB->Size < dwBase + Size || + UMB->Base > dwBase + Size)) { + UMB = UMB->Next; + } + + if (UMB == NULL) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } +#ifndef MONITOR + sas_connect_memory(dwBase, dwBase + Size - 1, SAS_VDD); +#else + PageSize = HOST_PAGE_SIZE; + PageCount = (USHORT)(Size / HOST_PAGE_SIZE); + PageMask = 1 << ((dwBase - UMB->Base) / HOST_PAGE_SIZE); + SectionOffset.HighPart = 0; + SectionOffset.LowPart = dwBase - UMB->Base; + for (; PageCount > 0; PageCount--, PageMask <<= 1) { + if ((UMB->Mask & PageMask) != 0) { + // this page has memory committed, unmap it first + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)dwBase + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + // finally make a view for the page without commitment + Status= NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *) &dwBase, + 0, + 0, + &SectionOffset, + &PageSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_EXECUTE_READWRITE + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + SectionOffset.LowPart += HOST_PAGE_SIZE; + dwBase += HOST_PAGE_SIZE; + } +#endif + + return TRUE; +} + +VOID UMBNotify( +unsigned char code +) +{ + return; +} + +// This function release the reserved EMM memory space to the caller +// After the call is made, the address space is FREE and the caller +// has to map the space immediately so that it won't be used by +// the system for storage allocation. +BOOL +GetUMBForEMM(VOID) +{ +#ifdef MONITOR + PUMBNODE UMB; + NTSTATUS Status; + UMB = UMBList; + + while (UMB!= NULL) { + if (UMB->Owner == UMB_OWNER_EMM) { + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)UMB->Base + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + UMB = UMB->Next; + } +#endif + return TRUE; +} +// This function reserves an address space for VDD +// Here we map a view of section for each page within the requested +// block. This was done because the VDD may want to allocate/deallocate +// physical memory page by page. +BOOL +VDDReserveUMB( +DWORD dwBase, +DWORD Size, +PUMBNODE UMB +) +{ + +#ifdef MONITOR + USHORT Count; + LARGE_INTEGER SectionOffset; + DWORD SizeView; + NTSTATUS Status; +#endif + + while (UMB != NULL) { + if (UMB->Owner == UMB_OWNER_NONE && + UMB->Base <= dwBase && + UMB->Base + UMB->Size >= dwBase + Size) + + break; + else + UMB = UMB->Next; + } + if (UMB == NULL){ + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + UMB = SpliceUMB(UMB, dwBase, Size, UMB_OWNER_VDD); + if (UMB == NULL) { + return FALSE; + } +#ifndef MONITOR + sas_connect_memory(dwBase, dwBase + Size - 1, SAS_VDD); +#else + Count = (USHORT)(Size / HOST_PAGE_SIZE); + SizeView = HOST_PAGE_SIZE; + SectionOffset.HighPart = 0; + SectionOffset.LowPart = dwBase - UMB_BASE_ADDRESS; + // map a view for each page. This is done becuase VDDs may commit + // and decommit memory for/from their memory hook and the system + // has 64KB alignment restriction for virtual memory APIs. + for (; Count > 0; Count--, dwBase += HOST_PAGE_SIZE, + SectionOffset.LowPart += HOST_PAGE_SIZE) { + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *)&dwBase, + 0, + 0, + &SectionOffset, + &SizeView, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + return FALSE; + } + } +#endif + return TRUE; +} + +// This helper function splice the given block into multiple +// sublocks(max, 3) and reserves each newly created subblock + +PUMBNODE +SpliceUMB( +PUMBNODE UMB, +DWORD dwBase, +DWORD Size, +WORD Owner +) +{ +#ifdef MONITOR + DWORD SizeView; + NTSTATUS Status; + LARGE_INTEGER SectionOffset; +#endif + + DWORD SizeBefore, SizeAfter; + PUMBNODE UMBBefore, UMBAfter; + + + + SizeBefore = dwBase - UMB->Base; + SizeAfter = UMB->Size - Size - SizeBefore; + UMBBefore = UMB; + if (SizeAfter > 0) { + // allocate new node(s) before we unmap the block + UMBAfter = (PUMBNODE) malloc(sizeof(UMBNODE)); + if (UMBAfter == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + UMBAfter->Size = SizeAfter; + UMBAfter->Base = dwBase + Size; + UMBAfter->Owner = UMB_OWNER_NONE; + UMBAfter->Next = UMB->Next; + UMB->Next = UMBAfter; + UMB->Size -= SizeAfter; + } + + if (SizeBefore > 0) { + UMBBefore = (PUMBNODE) malloc(sizeof(UMBNODE)); + if (UMBBefore == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + UMBBefore->Size = Size; + UMBBefore->Base = dwBase; + UMBBefore->Owner = Owner; + UMBBefore->Next = UMB->Next; + UMB->Next = UMBBefore; + UMB->Size = SizeBefore; + UMB->Owner = UMB_OWNER_NONE; + } + else { + UMB->Owner = Owner; + } + +#ifdef MONITOR + // unmap the entire block because we gona map a view for each subblock + Status = NtUnmapViewOfSection(NtCurrentProcess(), + (PVOID)UMB->Base + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + SectionOffset.HighPart = 0; + + if (SizeBefore > 0) { + SizeView = UMB->Size; + dwBase = UMB->Base; + SectionOffset.LowPart = dwBase - UMB_BASE_ADDRESS; + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *) &dwBase, + 0, + 0, + &SectionOffset, + &SizeView, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + } + if (SizeAfter > 0){ + dwBase = UMBAfter->Base; + SectionOffset.LowPart = dwBase - UMB_BASE_ADDRESS; + SizeView = UMBAfter->Size; + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *)&dwBase, + 0, + 0, + &SectionOffset, + &SizeView, + ViewUnmap, + MEM_DOS_LIM, + UMB_PAGE_PROTECTION + ); + if (!NT_SUCCESS(Status)) { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + } +#endif + return UMBBefore; +} + +// This function initialize UMB list. Every block in the UMA +// area are chained together in a single list +// Each node in the list is either UMB_OWNER_NONE or UMB_OWNER_ROM. +#ifndef MONITOR +BOOL +InitUMBList(VOID) +{ + PUMBNODE UMB, UMBNew; + static DWORD ROMs[] = { EGA_ROM_START, EGA_ROM_END, + BIOS_START, 0x100000 + }; + DWORD CurAddress; + USHORT Index; + + UMBList = NULL; + + CurAddress = UMB_BASE_ADDRESS; + Index = 0; + while (CurAddress < UMB_BASE_ADDRESS + UMB_MAX_OFFSET) { + UMBNew = (PUMBNODE) malloc(sizeof(UMBNODE)); + if (UMBNew == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + UMBNew->Base = CurAddress; + if (CurAddress == ROMs[Index]) { + UMBNew->Owner = UMB_OWNER_ROM; + UMBNew->Size = ROMs[Index + 1] - CurAddress; + Index += 2; + } + else { + UMBNew->Owner = UMB_OWNER_NONE; + UMBNew->Size = ROMs[Index] - CurAddress; + } + CurAddress += UMBNew->Size; + if (UMBList == NULL) { + UMBList = UMBNew; + } + else { + UMB->Next = UMBNew; + } + UMBNew->Next = NULL; + UMB = UMBNew; + + } +} + +#else +// this is for X86 environment +BOOL +InitUMBList(VOID) + +{ + OBJECT_ATTRIBUTES UMBObjAttr; + LARGE_INTEGER UMBSecSize; + NTSTATUS Status; + DWORD CurAddress, RomAddress, RomSize; + PUMBNODE UMB, UMBNew; + USHORT Index; + + UNICODE_STRING WorkString; + UCHAR KeyValueBuffer[KEY_VALUE_BUFFER_SIZE]; + HANDLE RegistryHandle; + ULONG ResultLength; + OBJECT_ATTRIBUTES ObjectAttributes; + PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor; + PCM_ROM_BLOCK BiosBlock; + + RtlInitUnicodeString( + &WorkString, + L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM" + ); + + // + // Set up and open KeyPath + // + + InitializeObjectAttributes( + &ObjectAttributes, + &WorkString, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + Status = NtOpenKey( + &RegistryHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + DbgPrint("InitUMBList: can't open \\Registry\\Machine\\Hardware\\Description\\System\n"); +#endif + return FALSE; + } + + // + // Get the data for the rom information + // + + RtlInitUnicodeString( + &WorkString, + CONFIG_DATA_STRING + ); + + Status = NtQueryValueKey( + RegistryHandle, + &WorkString, + KeyValueFullInformation, + (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer, + KEY_VALUE_BUFFER_SIZE, + &ResultLength + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + DbgPrint("InitUMBList: Got nothing from Configuration Data\n"); +#endif + NtClose(RegistryHandle); + return FALSE; + } + + // Locate registry data for this key + ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)KeyValueBuffer + + ((PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer)->DataOffset); + + // Verify data returned is large enough to contaim partial resource + // descriptor. + if ((((PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer)->DataLength < + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) || + (ResourceDescriptor->PartialResourceList.Count < 2)) + { + Index = 0; + } else { + PartialResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ( + (PUCHAR)ResourceDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + + ResourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize); + + + //Verify that there is a 2nd partial resource descriptor, and that it is + //large enough to contain a ROM block description + if (((PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer)->DataLength < + ((PUCHAR)PartialResourceDescriptor - + (PUCHAR)ResourceDescriptor + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + + sizeof(CM_ROM_BLOCK))) + { + NtClose(RegistryHandle); + return FALSE; + } + + //get pointer to the first rom desciption + BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + // how many rom blocks we have + Index = (USHORT) (PartialResourceDescriptor->u.DeviceSpecificData.DataSize / + sizeof(CM_ROM_BLOCK)); + + } + + InitializeObjectAttributes(&UMBObjAttr, + NULL, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + + UMBSecSize.LowPart = UMB_MAX_OFFSET; + UMBSecSize.HighPart = 0; + + // create a section for the UMB area. Note that the section + // includes ROM blocks. This was done because we will allow + // VDDs to put ROM blocks into UMB free list for other users. + Status = NtCreateSection(&UMBSectionHandle, + SECTION_MAP_WRITE|SECTION_MAP_EXECUTE, + &UMBObjAttr, + &UMBSecSize, + UMB_PAGE_PROTECTION, + SEC_RESERVE, + NULL + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + DbgPrint("UMB:Unable to create UMB section, Status = %lx\n", + Status); +#endif + return(FALSE); + } + + // Now we go through the whole 256KB area to create a list for + // each UMB(including ROM blocks) + + // This global variable points to the first node in the list + UMBList = NULL; + CurAddress = UMB_BASE_ADDRESS; + + while (Index > 0) { + // round down address to the previous page boundary + RomAddress = BiosBlock->Address & ~(HOST_PAGE_SIZE - 1); + // round up the size to next page boundary + RomSize = (BiosBlock->Size + + BiosBlock->Address - RomAddress + + HOST_PAGE_SIZE - 1 + ) & ~(HOST_PAGE_SIZE - 1); + // combine two blocks together if they overlap in page + if (Index > 1 && (RomAddress + RomSize) > BiosBlock[1].Address) { + BiosBlock[1].Size += BiosBlock[1].Address - BiosBlock->Address; + BiosBlock[1].Address = BiosBlock->Address; + BiosBlock++; + Index--; + continue; + } + + + if (CurAddress == RomAddress) { + UMBNew = CreateNewUMBNode(CurAddress, RomSize, UMB_OWNER_ROM); + if (UMBNew == NULL) + return FALSE; + CurAddress += RomSize; + BiosBlock++; + Index--; + } + else { + // make sure the block is in UMB area + if (RomAddress > CurAddress && + RomAddress <= UMB_BASE_ADDRESS + UMB_MAX_OFFSET){ + + UMBNew = CreateNewUMBNode(CurAddress, + RomAddress - CurAddress, + UMB_OWNER_NONE + ); + if (UMBNew == NULL) + return FALSE; + CurAddress = RomAddress; + } + // this block is not in UMB area, discard it + else { + BiosBlock++; + Index--; + continue; + } + } + if (UMBList == NULL) + UMBList = UMBNew; + else + UMB->Next = UMBNew; + + UMB = UMBNew; + } + if (CurAddress < UMB_BASE_ADDRESS + UMB_MAX_OFFSET) { + + UMBNew = CreateNewUMBNode(CurAddress, + UMB_BASE_ADDRESS + UMB_MAX_OFFSET - CurAddress, + UMB_OWNER_NONE + ); + if (UMBNew == NULL) + return FALSE; + if (UMBList == NULL) + UMBList = UMBNew; + else + UMB->Next = UMBNew; + } +} + +// create a new node for the new UMB block +// map the given address space to the UMB section if +// the umb is a RAM(owner = NONE) + +PUMBNODE CreateNewUMBNode +( +DWORD BaseAddress, +DWORD Size, +WORD Owner +) +{ + PUMBNODE UMBNew; + LARGE_INTEGER SectionOffset; + NTSTATUS Status; + + if ((UMBNew = (PUMBNODE) malloc(sizeof(UMBNODE))) != NULL) { + UMBNew->Base = BaseAddress; + UMBNew->Size = Size; + UMBNew->Mask = 0; + UMBNew->Owner = Owner; + UMBNew->Next = NULL; + + if (Owner == UMB_OWNER_NONE) { + SectionOffset.HighPart = 0; + SectionOffset.LowPart = BaseAddress - UMB_BASE_ADDRESS; + Status = NtMapViewOfSection(UMBSectionHandle, + NtCurrentProcess(), + (PVOID *)&BaseAddress, + 0, //zero bits + 0, // commit size + &SectionOffset, // section offset + &Size, // view size + ViewUnmap, + MEM_DOS_LIM, // + UMB_PAGE_PROTECTION + ); + + if (!NT_SUCCESS(Status)) { +#if DBG + DbgPrint("InitUMBList failed to map, Status = %lx\n", + Status); +#endif + free(UMBNew); + UMBNew = NULL; + } + } + + } + return UMBNew; +} + +#endif diff --git a/private/mvdm/softpc.new/host/src/nt_unix.c b/private/mvdm/softpc.new/host/src/nt_unix.c new file mode 100644 index 000000000..e89b10b81 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_unix.c @@ -0,0 +1,459 @@ +/***************************************************************************** +* nt_unix.c - miscellaneous stuff that may be needed. * +* File derived from hp_unix.c by Philippa Watson. * +* * +* This version is written/ported for New Technology OS/2 * +* by Andrew Watson * +* * +* Date pending due to ignorance * +* * +* (c) Copyright Insignia Solutions 1991 * +* * +*****************************************************************************/ + +#include <windows.h> +#include "host_def.h" +#include "insignia.h" +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <string.h> +#include <time.h> +#include <sys\types.h> +#include "xt.h" +#include CpuH +#include "timeval.h" +#include "error.h" +#include "sas.h" +#include "spcfile.h" +#include "idetect.h" +#include "debug.h" +#include "nt_reset.h" +#include "nt_pif.h" + + +/***************************************************************************** +* local #define used for stubbing out functions * +*****************************************************************************/ + +#define STUBBED 1 + +/**** externally visible global variable declarations ****/ + +extern char *_sys_errlist[]; +extern int _sys_nerr; + + +/* Exported Data */ +GLOBAL BOOL ExternalWaitRequest = FALSE; + + +/* Local Module Data */ +HANDLE IdleEvent = NULL; +DWORD MainThreadId = 0; +BOOL NowWaiting = FALSE; + +/***************************************************************************** +* Function: host_get_system_error() * +* This routine processes an error returned by SoftPC. * +* Returns a pointer to an error message (located in a table) that * +* corresponds to the error number passed as a parameter. * +*****************************************************************************/ + +LPSTR host_get_system_error(filename, line, error) +LPSTR filename; +DWORD line; +DWORD error; +{ +static BYTE buf[256]; + +if (error > (DWORD)_sys_nerr) + { + sprintf(buf, "System error %d occurred in %s (line %d)", + error, filename, line); + return(buf); + } +else + return(_sys_errlist[error]); +} + + +/* This section contains host side of idling system */ + +/***************************************************************************** +* Function: host_idle_init() * +* Create Event used in Idling Wait * +*****************************************************************************/ +void host_idle_init(void) +{ + if (IdleEvent != NULL) + return; //Called already + + MainThreadId = GetCurrentThreadId(); + + IdleEvent = CreateEvent((LPSECURITY_ATTRIBUTES) NULL, FALSE, FALSE, NULL); + +#ifndef PROD + if (IdleEvent == NULL) + printf("NTVDM:Idlling Event creation failed. Err %d\n",GetLastError()); +#endif +} + +/***************************************************************************** +* Function: WaitIfIdle() * +* If no counter indications (video, com etc) then do short idle * +* * +*****************************************************************************/ +void WaitIfIdle(void) +{ + DWORD idletime; + + if (IdleDisabledFromPIF) { + return; + } + + + /* + * If its not wow make sure the main thread also gets idled. + */ + if (!VDMForWOW && GetCurrentThreadId() != MainThreadId) + { + ExternalWaitRequest = TRUE; + } + + + // + // Check for invalid conditions + // + if (!IdleEvent || !IdleNoActivity) { + Sleep(0); + return; + } + + NowWaiting = TRUE; + idletime = ienabled ? 10 : 1; + + if (WaitForSingleObject(IdleEvent, idletime) == WAIT_FAILED) { + Sleep(0); + idletime = 0; + } + NowWaiting = FALSE; + +#ifndef MONITOR + if (idletime) { + ActivityCheckAfterTimeSlice(); + } +#endif + +} + + +/***************************************************************************** +* Function: WakeUpNow() * +* The paired counterpart to WaitIfIdle() - the event that was worth waiting * +* for has arrived. Wake CPU up so it can deal with it. * +*****************************************************************************/ +void WakeUpNow(void) +{ + HostIdleNoActivity(); +} + + + +/* HostIdleNoActivity + * + * Set Indicator that video\disk\com\lpt activity + * has happened and wake up sleeping CPU if appears to be sleeping. + */ +void HostIdleNoActivity(void) +{ + + IdleNoActivity=0; + + if (NowWaiting) // critical path do inline.... + PulseEvent(IdleEvent); +} + + + +/***************************************************************************** +* Function: host_release_timeslice() * +*****************************************************************************/ +void host_release_timeslice(void) +{ + DWORD idletime; + + // + // If there is counter idle activity no idling so return immediatly + // + if (!IdleNoActivity || IdleDisabledFromPIF) { + return; + } + + // + // Check for invalid or unsafe conditions + // + if (!IdleEvent || !ienabled) { + Sleep(0); + return; + } + + // + // If pif Foreground priority is set to less than 100 on every timer + // event PrioWaitIfIdle will do a wait, so use minimum delay here. + // + if (WNTPifFgPr < 100) { + idletime = 0; + } + + // + // Normal idling condition, so use sig portion of 55 ms time tick + // + else { + idletime = 25; + } + + NowWaiting = TRUE; + if (WaitForSingleObject(IdleEvent, idletime) == WAIT_FAILED) { + idletime = 0; + Sleep(0); + } + NowWaiting = FALSE; + +#ifndef MONITOR + if (idletime) { + ActivityCheckAfterTimeSlice(); + } +#endif + + + +} + + + +/***************************************************************************** +* Function: PrioWaitIfIdle(Percentage) * +* unsigned char Percentage - Percent of cpu usage desired +* The smaller the number the bigger the delay time +* +*****************************************************************************/ +void PrioWaitIfIdle(unsigned char Percentage) +{ + DWORD idletime; + + + // + // If there is counter idle activity no idling so return immediatly + // + if (!IdleNoActivity) { + return; + } + + // + // Check for invalid conditions + // + if (!IdleEvent) { + Sleep(0); + return; + } + + + idletime = (100 - Percentage) >> 1; // percent of 55ms time tick + + + // + // If idle is disabled, we can't depend on the IdleNoActivity flag + // or if the delay time is less than the system's time slice + // shorten the idle so we don't oversleep + // + if (!ienabled) + idletime >>= 2; + + if (idletime < 10) + idletime >>= 1; + + if (idletime) { + NowWaiting = TRUE; + if (WaitForSingleObject(IdleEvent, idletime) == WAIT_FAILED) { + idletime = 0; + Sleep(0); + } + NowWaiting = FALSE; + } + else { + Sleep(0); + } + +#ifndef MONITOR + if (idletime) { + ActivityCheckAfterTimeSlice(); + } +#endif + +} + + + + +/***************************************************************************** +* function: host_memset() * +* This function does what the traditional memset standard library function* +* does ... i.e. fills a portion of memory with the character represented * +* in val. * +* Returns nothing. * +*****************************************************************************/ + +void host_memset(addr, val, size) +register char * addr; +register char val; +unsigned int size; +{ +memset(addr, val, size); +} + + + +#ifdef NO_LONGER_USED +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + * Host-specific equivalent of the Unix function localtime(). + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +struct host_tm *host_localtime(clock) +long *clock; +{ + SYSTEMTIME now; + SAVED struct host_tm host_now; + + UNUSED(clock); + GetLocalTime(&now); + host_now.tm_sec = (int) now.wSecond; + host_now.tm_min = (int) now.wMinute; + host_now.tm_hour = (int) now.wHour; + host_now.tm_mday = (int) now.wDay; + host_now.tm_mon = (int) now.wMonth - 1; // Unix has 0 based months,NT 1 + host_now.tm_year = (int) now.wYear; + host_now.tm_wday = (int) now.wDayOfWeek; + + host_now.tm_yday = (int) 0; // the base doesn't require these. + host_now.tm_isdst = (int) 0; + return(&host_now); +} +#endif + +/* + * Host-specific equivalent of the Unix function time(). + */ + +long host_time(tloc) +long *tloc; +{ + UNUSED(tloc); + return((long) GetTickCount() / 1000 ); +} + +/* + * Check that the file is a character special device. + */ +boolean host_file_is_char_dev(path) +char *path; +{ + return(FALSE); +} + + +/* + * Looks for a given file name in the 'ntvdm' subdirectory of the + * windows system directory. The full path to the first one found is returned + * in the 'full_path' variable, and as the result of the function. + */ +char *host_find_file(file,full_path,display_error) +char *file,*full_path; +int display_error; +{ + char buffer[MAXPATHLEN]; + WIN32_FIND_DATA match; + HANDLE gotit; + static char sysdir[MAX_PATH]; + static int first = 1; + + if (first) + { + first = 0; + if (GetSystemDirectory(sysdir, MAXPATHLEN) == 0) + { + sysdir[0] = '\0'; + host_error(EG_SYS_MISSING_FILE, ERR_QUIT, file); + return(NULL); + } + } + + if (sysdir[0] != '\0') + { + strcpy(buffer, sysdir); + strcat(buffer, "\\"); + strcat(buffer, file); + } + + if ((gotit = FindFirstFile(buffer, &match)) != (HANDLE)-1) + { + FindClose(gotit); // should check (BOOL) return & then ?? + strcpy(full_path, buffer); + return (full_path); + } + + /* Haven't managed to find the file. Oh dear... */ + switch( display_error ) + { + case SILENT: + return( NULL ); + break; + + case STANDARD: + case CONT_AND_QUIT: + host_error(EG_SYS_MISSING_FILE, ERR_CONT | ERR_QUIT, file); + break; + + default: + host_error(EG_SYS_MISSING_FILE, ERR_QUIT, file); + break; + } + + return (NULL); +} + + + +// +// this stuff needs to be removed +// +static char temp_copyright[] = "SoftPC-AT Version 3\n\r(C)Copyright Insignia Solutions Inc. 1987-1992"; + +static int block_level = 0; + +GLOBAL void host_block_timer() +{ + if(block_level) return; + block_level++; +} + +GLOBAL void host_release_timer() +{ + block_level=0; +} +GLOBAL CHAR * host_get_years() +{ +return ("1987 - 1992"); +} +GLOBAL CHAR * host_get_version() +{ +return("3.00"); +} +GLOBAL CHAR * host_get_unpublished_version() +{ +return(""); +} +GLOBAL CHAR * host_get_copyright() +{ +return(""); +} diff --git a/private/mvdm/softpc.new/host/src/nt_vdd.c b/private/mvdm/softpc.new/host/src/nt_vdd.c new file mode 100644 index 000000000..6396f8cd2 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_vdd.c @@ -0,0 +1,821 @@ +/********************************************************/ +/* + * nt_vdd.c - NT support for VDD DLLs + * + * Ade Brownlow + * + * 19/11/91 + * + */ + +#include "windows.h" +#include "insignia.h" +#include "host_def.h" + +#include <stdio.h> + +#include "xt.h" +#include CpuH +#include "sas.h" +#include "error.h" +#include "config.h" + +#include "ios.h" +#include "dma.h" +#include "nt_vdd.h" +#include "nt_vddp.h" + + +#ifdef ANSI + +/* MS bop grabbing stuff */ +GLOBAL half_word get_MS_bop_index (void *); +GLOBAL void free_MS_bop_index (half_word); +GLOBAL void ms_bop (void); +LOCAL void ms_not_a_bop (void); + +/* IO slot grabbers */ +GLOBAL half_word io_get_spare_slot (void); +GLOBAL void io_release_spare_slot (half_word); +#else +/* MS bop grabbing stuff */ +GLOBAL half_word get_MS_bop_index (); +GLOBAL void free_MS_bop_index (); +GLOBAL void ms_bop (); +LOCAL void ms_not_a_bop (); + +/* IO slot grabbers */ +GLOBAL half_word io_get_spare_slot (); +GLOBAL void io_release_spare_slot (); +#endif + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::: Local data structures */ + +#define MAX_SLOTS (10) + +LOCAL void (*MS_bop_tab[MAX_SLOTS])(); /* MS bop table */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Microsoft BOP vectoring code references MS_bop_tab above and calls function + * as directed by AH */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL void ms_bop () /* called from MS_bop_5 ie bop 0x55 */ +{ + half_word ah = getAH(); /* get the value in AH */ + + /*........................................Valid then call the MS function */ + + if(ah >= MAX_SLOTS || MS_bop_tab[ah] == NULL) + ms_not_a_bop(); + else + (*MS_bop_tab[ah])(); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::: Dummy for unset AH values - stops us zipping into hyperspace :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +LOCAL void ms_not_a_bop() +{ +#ifndef PROD + printf ("AH=%x, This is not a valid value for an MS BOP\n", getAH()); + illegal_bop(); +#ifdef YODA + force_yoda (); +#endif +#endif +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Give an index to our table which can be used for the passed function :::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL half_word get_ms_bop_index (void (*func)()) +{ + register half_word index; + + for(index = 0; index < MAX_SLOTS; index++) + { + if(MS_bop_tab[index] == NULL) + { + MS_bop_tab[index] = func; + break; + } + } + + return (index == MAX_SLOTS ? (half_word) 0xff : index); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: free the bop index passed :::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL void free_MS_bop_index IFN1(half_word, index) +{ + MS_bop_tab[index] = NULL; +} + + +/* + * ========================================================================== + * Imports + * ========================================================================== + */ +IMPORT VOID host_ica_lock(), host_ica_unlock(); + +/********************************************************/ +/* IO stuff */ + + + // VddAdapter Table (Adapter X hVdd table) + // there is only one adapter per VDD +HANDLE VddAdapter[NUMBER_SPARE_ADAPTERS]; + +#define MAX_IRQ_LINE 15 +// Bugbug need to initialize this cleanly +HANDLE IrqLines[MAX_IRQ_LINE+1] = {(HANDLE)1, (HANDLE)1, (HANDLE)1, (HANDLE)1, + (HANDLE)1, (HANDLE)1, (HANDLE)1, (HANDLE)1, + (HANDLE)1, (HANDLE)1, (HANDLE)1, (HANDLE)0, + (HANDLE)0, (HANDLE)1, (HANDLE)1, (HANDLE)0}; + + +/* GetVddAdapter + * + * Retrieves the current adapter number for the Vdd + * If none is assigned, then one is assigned + * + * entry: HANDLE hVdd - handle forthe vdd + * exit : WORD wAdaptor - Assigned Adaptor Num + * (Zero for failure) + * WinLastError Codes: + * + * ERROR_ALREADY_EXISTS - Adaptor already exists for the Vdd + * ERROR_OUTOFMEMORY - No adaptor slots available + * + */ +WORD GetVddAdapter(HANDLE hVdd) +{ + WORD w; + + // + // search VddAdapter table to see if adapter already assigned + // + for (w = 0; w < NUMBER_SPARE_ADAPTERS; w++) + { + if (VddAdapter[w] == hVdd) { + SetLastError(ERROR_ALREADY_EXISTS); + return 0; + } + } + + // + // assume not assigned, so look for first available slot + // + for (w = 0; w < NUMBER_SPARE_ADAPTERS; w++) + { + if (VddAdapter[w] == 0) { + VddAdapter[w] = hVdd; + return (w + SPARE_ADAPTER1); + } + } + + // none found return error + SetLastError(ERROR_OUTOFMEMORY); + return 0; +} + + + +/* FreeVddAdapter + * + * Frees the current adaptor for the specified VDD + * + * entry: HANDLE hVdd + * exit: WORD AdaptorNumber that was freed, + * Zero for not found + * + */ +WORD FreeVddAdapter(HANDLE hVdd) +{ + WORD w; + + // + // search VddAdapter table by hVdd for adaptor + // and mark it as available + // + w = NUMBER_SPARE_ADAPTERS; + while (w--) + { + if (VddAdapter[w] == hVdd) { + VddAdapter[w] = 0; + return w; + } + } + + return 0; +} + +#ifdef MONITOR +extern BOOLEAN MonitorVddConnectPrinter(WORD Adapter, HANDLE hVdd, BOOLEAN Connect); +#endif /* MONITOR */ + + +/*** VDDInstallIOHook - This service is provided for VDDs to hook the + * IO ports they are responsible for. + * + * INPUT: + * hVDD ; VDD Handle + * cPortRange; Number of VDD_IO_PORTRANGE structures + * pPortRange; Pointer to array of VDD_IO_PORTRANGE + * IOhandler : VDD handler for the ports. + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * NOTES: + * 1. The first one to hook a port will get control. Subsequent + * requests will be failed. There is no concept of chaining + * the hooks. + * + * 2. IOHandler must atleast provide a byte read and a byte write + * handler. Others can be NULL. + * + * 3. If word or string handlers are not provided, their effect + * will be emulated using byte handlers. + * + * 4. VDDs should not hook DMA ports. NTVDM manages it for all + * the clients and services are provided to perform DMA + * operations and to access and modify DMA data. + * + * 5. VDDs should not hook video ports as well. Such a hooking + * will succeed but there is no gurantee that the IO handler will + * get called. + * + * 6. Each Vdd is allowed to install only one set of IO hooks + * at a time. + * + * 7. Extended Error codes: + * + * ERROR_ACCESS_DENIED - One of the requested ports is already hooked + * ERROR_ALREADY_EXISTS - Vdd already has active IO port handlers + * ERROR_OUTOFMEMORY - Insufficient resources for additional VDD + * Port handler set. + * ERROR_INVALID_ADDRESS - One of the IO port handlers has an invalid + * address. + */ +BOOL VDDInstallIOHook ( + HANDLE hVdd, + WORD cPortRange, + PVDD_IO_PORTRANGE pPortRange, + PVDD_IO_HANDLERS pIOFn) +{ + WORD w, i; + WORD wAdapter; + PVDD_IO_PORTRANGE pPRange; +#ifdef MONITOR + WORD lptAdapter = 0; +#endif + + + // check parameters + // the inb and outb handlers must be valid + // the rest must be either NULL or valid + // + if (IsBadCodePtr((FARPROC)pIOFn->inb_handler) || + IsBadCodePtr((FARPROC)pIOFn->outb_handler)) + { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + if ((pIOFn->inw_handler && IsBadCodePtr((FARPROC)pIOFn->inw_handler)) || + (pIOFn->insb_handler && IsBadCodePtr((FARPROC)pIOFn->insb_handler)) || + (pIOFn->insw_handler && IsBadCodePtr((FARPROC)pIOFn->insw_handler)) || + (pIOFn->outw_handler && IsBadCodePtr((FARPROC)pIOFn->outw_handler)) || + (pIOFn->outsb_handler && IsBadCodePtr((FARPROC)pIOFn->outsb_handler))|| + (pIOFn->outsw_handler && IsBadCodePtr((FARPROC)pIOFn->outsw_handler)) ) + { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + // Get an adapter + wAdapter = GetVddAdapter(hVdd); + if (!wAdapter) { + return FALSE; + } + + // register io handlers for this adapter + io_define_in_routines((half_word)wAdapter, + pIOFn->inb_handler, + pIOFn->inw_handler, + pIOFn->insb_handler, + pIOFn->insw_handler); + + io_define_out_routines((half_word)wAdapter, + pIOFn->outb_handler, + pIOFn->outw_handler, + pIOFn->outsb_handler, + pIOFn->outsw_handler); + + // register ports for this adapter\vdd + i = cPortRange; + pPRange = pPortRange; + while (i) { + for (w = pPRange->First; w <= pPRange->Last; w++) + { +#ifdef MONITOR + // watch out for lpt ports + // note that the vdd must hook every port assoicated with + // the lpt. Just imanging that the vdd traps the control + // port while leaves the rest for softpc-- we are going + // to screw up badly and so does the vdd. + // QUESTION: How can we enforece this???? + if (w >= LPT1_PORT_START && w < LPT1_PORT_END) + lptAdapter |= 1; + else if (w >= LPT2_PORT_START && w < LPT2_PORT_END) + lptAdapter |= 2; + else if (w >= LPT3_PORT_START && w < LPT3_PORT_END) + lptAdapter |= 4; +#endif + if (!io_connect_port(w, (half_word)wAdapter, IO_READ_WRITE)) + { + // if one of the port connects failed + // undo the connects that succeeded and ret error + i = w; + while (pPortRange < pPRange) { + for (w = pPortRange->First; w <= pPortRange->Last; w++) + { + io_disconnect_port(w, (half_word)wAdapter); + } + pPortRange++; + } + + for (w = pPortRange->First; w < i; w++) + { + io_disconnect_port(w, (half_word)wAdapter); + } + + FreeVddAdapter(hVdd); + + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + pPRange++; + i--; + } + +#ifdef MONITOR +// i/o ports are hooked successfully, stop printer status port +// kernel emulation if the they are in the hooked range + if (lptAdapter & 1) + MonitorVddConnectPrinter(0, hVdd, TRUE); + if (lptAdapter & 2) + MonitorVddConnectPrinter(1, hVdd, TRUE); + if (lptAdapter & 4) + MonitorVddConnectPrinter(2, hVdd, TRUE); +#endif /* MONITOR */ + return TRUE; +} + + + +/*** VDDDeInstallIOHook - This service is provided for VDDs to unhook the + * IO ports they have hooked. + * + * INPUT: + * hVDD : VDD Handle + * + * OUTPUT + * None + * + * NOTES + * + * 1. On Deinstalling a hook, the defult hook is placed back on + * those ports. Default hook returns 0xff on reading + * and ignores the write operations. + * + */ +VOID VDDDeInstallIOHook ( + HANDLE hVdd, + WORD cPortRange, + PVDD_IO_PORTRANGE pPortRange) +{ + WORD w; + WORD wAdapter; +#ifdef MONITOR + WORD lptAdapter = 0; +#endif + + + wAdapter = FreeVddAdapter(hVdd); + if (!wAdapter) { + return; + } + + + // deregister ports for this adapter\vdd + while (cPortRange--) { + for (w = pPortRange->First; w <= pPortRange->Last; w++) + { +#ifdef MONITOR + // watch out for lpt status ports + // note that the vdd must unhook every port assoicated with + // the lpt. Just imanging that the vdd traps the control + // port while leaves the rest for softpc-- we are going + // to screw up badly and so does the vdd. + // QUESTION: How can we enforece this???? + if (w >= LPT1_PORT_START && w < LPT1_PORT_END) + lptAdapter |= 1; + else if (w >= LPT2_PORT_START && w < LPT2_PORT_END) + lptAdapter |= 2; + else if (w >= LPT3_PORT_START && w < LPT3_PORT_END) + lptAdapter |= 4; +#endif + io_disconnect_port(w, (half_word)wAdapter); + } + pPortRange++; + } + +#ifdef MONITOR +// i/o ports are Unhooked successfully, resume printer status port +// kernel emulation if the they are in the hooked range + if (lptAdapter & 1) + MonitorVddConnectPrinter(0, hVdd, FALSE); + if (lptAdapter & 2) + MonitorVddConnectPrinter(1, hVdd, FALSE); + if (lptAdapter & 4) + MonitorVddConnectPrinter(2, hVdd, FALSE); +#endif /* MONITOR */ +} + + +/*** VDDReserveIrqLine - This service resolves contention between VDDs + * over Irq lines. + * + * Parameters: + * hVDD : VDD Handle + * IrqLine ; the specific IrqLine number to reserve, or -1 to search for + * a free line. + * + * Return Value + * VDDReserveIrqLine returns the IrqLine number (0-15) if successful. + * Otherwise, this function returns 0xFFFF and logs an error. The + * extended error code will be ERROR_INVALID_PARAMETER. + * + * Comments: + * The value of an IrqLine number may range from 0-15 and correspond to + * the irq line numbers of the virtual PICs (8259) emulated by the ntvdm + * subsystem. Many of the line numbers are already used by the system + * (e.g. for Timer, Keyboard, etc.), but there are a few free lines. VDDs + * can take advantage of this and use the VDDSimulateInterrupt service to + * reflect virtual interrupts specific to that VDD. This service provides + * a way to manage the contention for the free irq lines. + * + * This service does not prevent VDDs that do not own a given IrqLine from + * calling VDDSimulateInterrupt specifying that IrqLine. So it is important + * to rely on this service, rather than expecting VDDSimulateInterrupt to + * fail, to determine that a given IrqLine is available for use. + * + * This service may be called at any time. Typically, VDDs will use this + * service at init time, and pass the number of the reserved IrqLine to + * the vdm application/driver code. This code can then hook the corresponding + * interrupt vector (8-15, 70-77) using the DOS Set Vector function + * (Int 21h, func 25h) in order to handle the interrupts generated with + * the VDDSimulateInterrupt service. + */ +WORD VDDReserveIrqLine ( + HANDLE hVdd, + WORD IrqLine) +{ + + WORD ReturnValue = 0xFFFF; + + if ((!hVdd) || + ((IrqLine > MAX_IRQ_LINE) && (IrqLine != 0xFFFF)) ) { + + SetLastError(ERROR_INVALID_PARAMETER); + return(ReturnValue); + } + + host_ica_lock(); // acquire critical section + + if (IrqLine == 0xFFFF) { + + for (IrqLine = MAX_IRQ_LINE; IrqLine < 0xFFFF; IrqLine--) { + if (IrqLines[IrqLine] == 0) { + IrqLines[IrqLine] = hVdd; + ReturnValue = IrqLine; + break; + } + } + + } else if (IrqLines[IrqLine] == 0) { + + IrqLines[IrqLine] = hVdd; + ReturnValue = IrqLine; + } + + host_ica_unlock(); + + if (ReturnValue == 0xFFFF) + SetLastError(ERROR_INVALID_PARAMETER); + + return(ReturnValue); +} + +/*** VDDReleaseIrqLine - This service releases a lock on an Irq Line + * obtained with VDDReserveIrqLine + * + * Parameters: + * hVDD : VDD Handle + * IrqLine : The specific IrqLine number (0-15) to release. + * + * Return Value: + * VDDReleaseIrqLine returns TRUE if successful. + * Otherwise, this function returns FALSE and logs an error. The + * extended error code will be ERROR_INVALID_PARAMETER. + * + * Comments: + * Upon successful execution of this function, the specified IrqLine will + * be available to other VDDs. + * + * This service may be called at any time. + */ +BOOL VDDReleaseIrqLine ( + HANDLE hVdd, + WORD IrqLine) +{ + + BOOL Status = FALSE; + + if ((!hVdd) || + (IrqLine > MAX_IRQ_LINE) ) { + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + + } + + host_ica_lock(); // acquire critical section + + if (IrqLines[IrqLine] == hVdd) { + IrqLines[IrqLine] = 0; + Status = TRUE; + } + + host_ica_unlock(); + + if (!Status) + SetLastError(ERROR_INVALID_PARAMETER); + + return(Status); +} + + +/********************************************************/ +/* DMA stuff */ + + + +/*** VDDRequestDMA - This service is provided for VDDs to request a DMA + * transfer. + * + * INPUT: + * hVDD VDD Handle + * iChannel DMA Channel on which the operation to take place + * Buffer Buffer where to or from transfer to take place + * length Transfer Count (in bytes) + * + * If Zero, returns the Current VDMA transfer count + * in bytes. + * + * OUTPUT + * DWORD returns bytes transferred + * if Zero check GetLastError to determine if the + * call failed or succeeded + * GetLastError has the extended error information. + * + * NOTES + * 1. This service is intended for those VDDs which do not want to + * carry on the DMA operation on their own. Carrying on a DMA + * operation involves understanding all the DMA registers and + * figuring out what has to be copied, from where and how much. + * + * 2. This service will be slower than using VDDQueryDMA/VDDSetDMA and + * doing the transfer on your own. + * + * 3. Extended Error codes: + * + * ERROR_ALREADY_EXISTS - Vdd already has active IO port handlers + * ERROR_OUTOFMEMORY - Insufficient resources for additional VDD + * Port handler set. + * ERROR_INVALID_ADDRESS - One of the IO port handlers has an invalid + * address. + * + */ +DWORD VDDRequestDMA ( + HANDLE hVDD, + WORD iChannel, + PVOID Buffer, + DWORD length ) +{ + DMA_ADAPT *pDmaAdp; + DMA_CNTRL *pDcp; + WORD Chan; + WORD Size; + WORD tCount; + BOOL bMore; + + + if (iChannel > DMA_CONTROLLER_CHANNELS*DMA_ADAPTOR_CONTROLLERS) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + pDmaAdp = dmaGetAdaptor(); + pDcp = &pDmaAdp->controller[dma_physical_controller(iChannel)]; + Chan = dma_physical_channel(iChannel); + Size = dma_unit_size(iChannel); + + // if the controller or the channel is disabled, return 0 + if (pDcp->command.bits.controller_disable == 1 || + (pDcp->mask & (1 << Chan)) == 0) + return (0); + + tCount = ((WORD)pDcp->current_count[Chan][1] << 8) + | (WORD)pDcp->current_count[Chan][0]; + + SetLastError(0); // assume success + + // return requested transfer count (in bytes) + if (!length) { + return (DWORD)Size*((DWORD)tCount + 1); + } + + length = length/Size - 1; + + if (length > 0xFFFF) { + length = 0xFFFF; + } + + try { + bMore = (BOOL) dma_request((half_word)iChannel, + Buffer, + (word) length); + } + except(EXCEPTION_EXECUTE_HANDLER) { + SetLastError(ERROR_INVALID_ADDRESS); + return 0; + } + + if (!bMore) { // terminal count has been reached + return ((DWORD)tCount+1) * (DWORD)Size; + } + + tCount -= ((WORD)pDcp->current_count[Chan][1] << 8) + | (WORD)pDcp->current_count[Chan][0]; + + return ((DWORD)tCount + 1) * (DWORD)Size; +} + + + + + +/*** VDDQueryDMA - This service is provided for VDDs to collect all the DMA + * data. + * + * INPUT: + * hVDD VDD Handle + * iChannel DMA Channel for which to query + * Buffer Buffer where information will be returned + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * + * NOTES + * 1. This service is intended for those VDD which are doing + * performance critical work. These VDD can do their own DMA + * transfers and avoid one extra buffer copying which is a + * overhead in using VDDRequestDMA. + * + * 2. VDDs should use VDDSetDMA to properly update the state of + * DMA after carrying on the operation. + * + * 3. Extended Error codes: + * + * ERROR_INVALID_ADDRESS - Invalid channel + * + */ +BOOL VDDQueryDMA ( + HANDLE hVDD, + WORD iChannel, + PVDD_DMA_INFO pDmaInfo) +{ + DMA_ADAPT *pDmaAdp; + DMA_CNTRL *pDcp; + WORD Chan; + + + if (iChannel > DMA_CONTROLLER_CHANNELS*DMA_ADAPTOR_CONTROLLERS) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + pDmaAdp = dmaGetAdaptor(); + pDcp = &pDmaAdp->controller[dma_physical_controller(iChannel)]; + Chan = dma_physical_channel(iChannel); + + + pDmaInfo->addr = ((WORD)pDcp->current_address[Chan][1] << 8) + | (WORD)pDcp->current_address[Chan][0]; + + pDmaInfo->count = ((WORD)pDcp->current_count[Chan][1] << 8) + | (WORD)pDcp->current_count[Chan][0]; + + pDmaInfo->page = (WORD) pDmaAdp->pages.page[iChannel]; + pDmaInfo->status = (BYTE) pDcp->status.all; + pDmaInfo->mode = (BYTE) pDcp->mode[Chan].all; + pDmaInfo->mask = (BYTE) pDcp->mask; + + + return TRUE; +} + + + + +/*** VDDSetDMA - This service is provided for VDDs to set the DMA data. + * + * INPUT: + * hVDD VDD Handle + * iChannel DMA Channel for which to query + * fDMA Bit Mask indicating which DMA data fields are to be set + * VDD_DMA_ADDR + * VDD_DMA_COUNT + * VDD_DMA_PAGE + * VDD_DMA_STATUS + * Buffer Buffer with DMA data + * + * OUTPUT + * SUCCESS : Returns TRUE + * FAILURE : Returns FALSE + * GetLastError has the extended error information. + * + * NOTES + * + * 1. Extended Error codes: + * + * ERROR_INVALID_ADDRESS - Invalid channel + * + */ +BOOL VDDSetDMA ( + HANDLE hVDD, + WORD iChannel, + WORD fDMA, + PVDD_DMA_INFO pDmaInfo) +{ + DMA_ADAPT *pDmaAdp; + DMA_CNTRL *pDcp; + WORD Chan; + + + if (iChannel > DMA_CONTROLLER_CHANNELS*DMA_ADAPTOR_CONTROLLERS) { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + + pDmaAdp = dmaGetAdaptor(); + pDcp = &pDmaAdp->controller[dma_physical_controller(iChannel)]; + Chan = dma_physical_channel(iChannel); + + if (fDMA & VDD_DMA_ADDR) { + pDcp->current_address[Chan][1] = (half_word)HIBYTE(pDmaInfo->addr); + pDcp->current_address[Chan][0] = (half_word)LOBYTE(pDmaInfo->addr); + } + + if (fDMA & VDD_DMA_COUNT) { + pDcp->current_count[Chan][1] = (half_word)HIBYTE(pDmaInfo->count); + pDcp->current_count[Chan][0] = (half_word)LOBYTE(pDmaInfo->count); + } + + if (fDMA & VDD_DMA_PAGE) { + pDmaAdp->pages.page[iChannel] = (half_word)pDmaInfo->page; + } + + if (fDMA & VDD_DMA_STATUS) { + pDcp->status.all = (BYTE) pDmaInfo->status; + } + + + return TRUE; +} diff --git a/private/mvdm/softpc.new/host/src/nt_vflop.c b/private/mvdm/softpc.new/host/src/nt_vflop.c new file mode 100644 index 000000000..48726d4e0 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_vflop.c @@ -0,0 +1,604 @@ +#include "host_dfs.h" + + +#ifdef VFLOPPY +/***************************************************************************** +* nt_vflop.c - virtual floppy disk provision for Microsoft(tm). * +* * +* File derived from gfi_vflop.c by Henry Nash. * +* * +* This version is written/ported for New Technology OS/2 * +* by Andrew Watson * +* * +* Modified so that only a single drive (B:) is available to prevent * +* an accidental floppy boot. * +* * +* Date pending due to ignorance * +* * +* (c) Copyright Insignia Solutions 1991 * +* * +*****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <io.h> +#include <fcntl.h> +#include <sys\types.h> +#include <sys\stat.h> + +#define L_SET 0 + +/* + * SoftPC include files + */ +#include "xt.h" +#include CpuH +#include "sas.h" +#include "bios.h" +#include "ios.h" +#include "trace.h" +#include "fla.h" +#include "dma.h" +#include "gfi.h" +#include "config.h" + +extern boolean gain_ownership(); +extern void release_ownership(); + +/* + * First - description of the PC disk/diskette in standard PC-DOS format + */ + +#define PC_BYTES_PER_SECTOR 512 +#define PC_TRACKS_PER_DISKETTE 40 +#define PC_HEADS_PER_DISKETTE 2 +#define PC_SECTORS_PER_DISKETTE_TRACK 9 + +/* + * The Maximum number of sectors per diskette that the FDC will support + */ + +#define PC_MAX_SECTORS_PER_DISKETTE_TRACK 12 +#define PC_MAX_BYTES_PER_SECTOR 4096 + + + +/* + * ... and where the diskettes resides under UNIX + */ + +#define BS_DISKETTE_NAME "c:\\softpc\\pctool.A" + +#define BS_DISKETTE_DOS_SID_NAME "c:\\softpc\\dos.SID" +#define BS_DISKETTE_SID_NAME "c:\\softpc\\pctool.SID" + + +/* + * The disk buffer used for moving between memory and the UNIX file. + * Currently this can opnly be one sector - but this could be easily + * increased if performance dictates. + */ + +#define BS_DISK_BUFFER_SIZE 1 /* in sectors */ + +half_word bs_disk_buffer[PC_MAX_BYTES_PER_SECTOR * BS_DISK_BUFFER_SIZE]; + +/* + * Each virtual disk has a flag to say if the UNIX file is open + */ + +static int bs_diskette_open = FALSE; + +/* + * Each virtual disk has a file descriptor + */ + +static int bs_diskette_fd; + +/* + * A virtual disk is read only if the Unix protection flag dictate it. + */ + +static boolean diskette_read_only; + + +/* + * The structure of an entry in the Sector Mapping Table + */ + +typedef struct + { + half_word no_of_sectors; + half_word sector_ID[PC_MAX_SECTORS_PER_DISKETTE_TRACK]; + word bytes_per_sector; + double_word start_position; + } +SID_ENTRY; + +/* + * The table itself - an entry for each track and head combination. + * It is filled in by the fl_read_SID() function at run time. + */ + +static SID_ENTRY fl_track_index[PC_TRACKS_PER_DISKETTE][PC_HEADS_PER_DISKETTE]; + +/* + * Table to convert the N format number into bytes per sector. The first + * location is not used as N starts at 1. + */ + +static word fl_sector_sizes[] = {0,256,512,1024,2048,4096} ; +static void fl_read_SID(); +static short fl_sector_check(); + +/* + * Global variable for name of diskette file + */ +char diskette_name[256]; + +/* + * A macro to calculate the sector offset from the start of the UNIX virtual + * diskette file for a given track and sector. This uses the track mapping + * table to find the start of the track. + */ + +#define diskette_position(track, head, sector, bytes_per_sector) \ + (fl_track_index[track][head].start_position + \ + ((sector - 1) * bytes_per_sector)) + +/* + * A macro returning TRUE if the drive is empty + */ + +#define drive_empty() (strcmp(diskette_name, "empty drive") == 0) + +static char *prog_name ="gfi_vfloppy:"; + +static int gfi_vdiskette_command(); +static int gfi_vdiskette_drive_on(); +static int gfi_vdiskette_drive_off(); +static int gfi_vdiskette_reset(); + + +/* + * ============================================================================ + * External functions + * ============================================================================ + */ + + +void gfi_vdiskette_init(drive) +int drive; +{ +/* + * Allow only the use of drive B: + * + * 1 - Drive A + * 1 - Drive B + */ + +if(drive!=1) + drive=1; + +gfi_function_table[drive].command_fn = gfi_vdiskette_command; +gfi_function_table[drive].drive_on_fn = gfi_vdiskette_drive_on; +gfi_function_table[drive].drive_off_fn = gfi_vdiskette_drive_off; +gfi_function_table[drive].reset_fn = gfi_vdiskette_reset; +} + + +void gfi_vdiskette_term(drive) +int drive; /* Currently parameter is ignored */ +{ +if (bs_diskette_open) + { + release_ownership(bs_diskette_fd); + close(bs_diskette_fd); + bs_diskette_open = FALSE; + } +} + +void fl_int_reset() +{ +/* + * Reset function for use by the 'Change Diskette function' + * and the standard floppy reset function. Also called by + * 'X_input.c' by 'new_disk()' when a new diskette is + * selected. + * No PC registers are modified in this function. + * + * Reset the virtual diskette by re-opening the file. + * + * First, if the file is open - close it. + */ +char dpath[MAXPATHLEN]; + +if (bs_diskette_open) + { + release_ownership(bs_diskette_fd); + close(bs_diskette_fd); + bs_diskette_open = FALSE; + } +strcpy(dpath, configuration.cf_fl_dir); +strcat(dpath, "\\"); +strcat(dpath, diskette_name); + + +bs_diskette_open = TRUE; /* Assume success */ +diskette_read_only = FALSE; /* Assume read/write */ + +bs_diskette_fd = open(dpath,O_RDWR,0); + +if (bs_diskette_fd < 0) + { + bs_diskette_fd = open(dpath, O_RDONLY,0); + if (bs_diskette_fd >= 0) + diskette_read_only = TRUE; + else + { + bs_diskette_open = FALSE; + fprintf(trace_file, "%s open error: %s\n", prog_name, dpath); + return; + } + } + +/* + * Now open the Sector ID file + */ + +fl_read_SID(diskette_name); +} +/* + * ============================================================================ + * Internal functions + * ============================================================================ + */ + +static int gfi_vdiskette_command(command_block, result_block) +FDC_CMD_BLOCK *command_block; +FDC_RESULT_BLOCK *result_block; +{ + half_word temp; + int source_start; + sys_addr destination_start; + sys_addr dma_address; + sys_addr pos; + int transfer_count; + int status; + int sector_index; + int bytes_per_sector; + int sector_count = 0; + word dma_size; + half_word C, H, R, N; + int track_info; + int i; + int ret_stat = SUCCESS; + boolean failed = FALSE; + + switch(command_block->type.cmd) { + case FDC_READ_DATA: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file,"%s Read Data Command \n", prog_name); + dma_enquire(DMA_DISKETTE_CHANNEL, &dma_address, &dma_size); + sector_index = fl_sector_check(command_block->c0.cyl, + command_block->c0.hd, + command_block->c0.sector); + if (sector_index == -1) { + /* + * Sector not found + */ + result_block->c0.ST0 = 0x40; + result_block->c0.ST1 = 0x00; + result_block->c1.ST1_no_data = 1; + result_block->c0.ST2 = 0x00; + } + else { + bytes_per_sector = fl_sector_sizes[command_block->c0.N]; + source_start = diskette_position(command_block->c0.cyl, + command_block->c0.hd, + sector_index, + bytes_per_sector); + transfer_count = (dma_size + 1) / bytes_per_sector; + + /* + * First SEEK to the start position + */ + + if (lseek(bs_diskette_fd, source_start, L_SET) < 0) + fprintf(trace_file, "%s Seek failed\n", prog_name); + else { + gain_ownership(bs_diskette_fd); + while(!failed && sector_count < transfer_count) { + /* + * Read sectors one by one into memory + * via the disk buffer + */ + status = read(bs_diskette_fd, + bs_disk_buffer, bytes_per_sector); + if (status != bytes_per_sector) + fprintf(trace_file, "%s Read failed\n", prog_name); + else + dma_request(DMA_DISKETTE_CHANNEL, + bs_disk_buffer, bytes_per_sector); + sector_count++; + } + } + result_block->c0.ST0 = 0x04; + result_block->c0.ST1 = 0x00; + result_block->c0.ST2 = 0x00; + } + result_block->c0.cyl = command_block->c0.cyl; + result_block->c0.head = command_block->c0.hd; + result_block->c0.sector = ((command_block->c0.sector - 1 + transfer_count) % PC_SECTORS_PER_DISKETTE_TRACK) + 1; + result_block->c0.N = command_block->c0.N; + break; + + case FDC_WRITE_DATA: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file,"%s Write Data Command \n", prog_name); + + dma_enquire(DMA_DISKETTE_CHANNEL, &dma_address, &dma_size); + sector_index = fl_sector_check(command_block->c0.cyl, + command_block->c0.hd, + command_block->c0.sector); + bytes_per_sector = fl_sector_sizes[command_block->c0.N]; + destination_start = diskette_position(command_block->c0.cyl, + command_block->c0.hd, + sector_index, + bytes_per_sector); + transfer_count = (dma_size + 1) / bytes_per_sector; + + /* + * First SEEK to the start position + */ + + if (lseek(bs_diskette_fd, destination_start, L_SET) < 0) + fprintf(trace_file, "%s Seek failed\n", prog_name); + else { + gain_ownership(bs_diskette_fd); + while(!failed && sector_count < transfer_count) { + /* + * Write sectors one by one from memory via the disk buffer + */ + dma_request(DMA_DISKETTE_CHANNEL, + bs_disk_buffer, bytes_per_sector); + status = write(bs_diskette_fd, + bs_disk_buffer, bytes_per_sector); + if (status != bytes_per_sector) { + failed = TRUE; + } + sector_count++; + } + } + result_block->c0.ST0 = 0x00; /* Clear down result bytes */ + result_block->c0.ST1 = 0x00; + + if (failed) { + result_block->c1.ST0_int_code = 1; + result_block->c1.ST1_write_protected = 1; + } + else { + result_block->c1.ST0_head_address = 1; + result_block->c0.ST1 = 0x00; + } + result_block->c0.ST2 = 0x00; + result_block->c0.cyl = command_block->c0.cyl; + result_block->c0.head = command_block->c0.hd; + result_block->c0.sector = ((command_block->c0.sector - 1 + transfer_count) % PC_SECTORS_PER_DISKETTE_TRACK) + 1; + result_block->c0.N = command_block->c0.N; + break; + + case FDC_READ_TRACK: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file,"%s Read Track Command \n", prog_name); + + break; + + case FDC_SPECIFY: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Specify command\n", prog_name); + break; + + case FDC_RECALIBRATE: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Recalibrate command\n", prog_name); + + result_block->c3.ST0 = 0; + result_block->c1.ST0_int_code = 0; + result_block->c1.ST0_seek_end = 0; + result_block->c1.ST0_unit = command_block->c5.drive; + result_block->c3.PCN = 0; + break; + + case FDC_SENSE_DRIVE_STATUS: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Sense Drive Status command\n", prog_name); + + result_block->c2.ST3_fault = 0; + result_block->c2.ST3_write_protected = diskette_read_only; + result_block->c2.ST3_ready = 1; + result_block->c2.ST3_track_0 = 0; + result_block->c2.ST3_two_sided = 1; + result_block->c2.ST3_head_address = 0; + result_block->c2.ST3_unit = command_block->c7.drive; + break; + + case FDC_SEEK: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Seek command\n", prog_name); + result_block->c3.ST0 = 0; + + if (drive_empty()) { + result_block->c1.ST0_int_code = 1; + result_block->c1.ST0_seek_end = 0; + result_block->c1.ST0_unit = command_block->c8.drive; + ret_stat = FAILURE; + } + else { + result_block->c1.ST0_int_code = 0; + result_block->c1.ST0_seek_end = 1; + result_block->c1.ST0_unit = command_block->c8.drive; + result_block->c3.PCN = command_block->c8.new_cyl; + } + break; + + case FDC_FORMAT_TRACK: + if (diskette_read_only) { + result_block->c1.ST0_int_code = 1; + result_block->c1.ST1_write_protected = 1; + } + else { + dma_enquire(DMA_DISKETTE_CHANNEL, &dma_address, &dma_size); + for ( i=0; i<command_block->c3.SC; i++) { + sas_load(dma_address++, &C); + sas_load(dma_address++, &H); + sas_load(dma_address++, &R); + sas_load(dma_address++, &N); + fprintf(trace_file, + "%s Format track: trk %x hd %x sector %x N_format %x\n", + prog_name, C, H, R, N); + } + } + break; + + default: + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Un-implemented command, type %x\n", + prog_name, command_block->type.cmd); + } + + return(ret_stat); +} + + +static int gfi_vdiskette_drive_on(drive) +int drive; +{ +#ifndef PROD + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Drive on command - drive %x\n", prog_name, drive); +#endif + + return(SUCCESS); +} + +static int gfi_vdiskette_drive_off(drive) +int drive; +{ +#ifndef PROD + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Drive off command - drive %x\n", prog_name, drive); +#endif + + return(SUCCESS); +} + + +static int gfi_vdiskette_reset(result_block) +FDC_RESULT_BLOCK *result_block; +{ +#ifndef PROD + if (io_verbose & GFI_VERBOSE) + fprintf(trace_file, "%s Reset command\n", prog_name); +#endif + + /* + * First reset the virtual diskette by closing and opening the file + */ + + fl_int_reset(); + + /* + * Fake up the Sense Interrupt Status result phase. We don't know the + * Present Cylinder No, so leave as zero. + */ + + result_block->c3.ST0 = 0; + result_block->c3.PCN = 0; + + return(SUCCESS); +} + + +static short fl_sector_check(track, head, sector) +half_word track; +half_word head; +half_word sector; +{ + /* + * Check the sector ID's in the mapping table for this track and head. + * Return -1 if the sector is not found, else the sector index with + * respect to the start of the track. + */ + + int i = 0; + int found = FALSE; + + while (i < fl_track_index[track][head].no_of_sectors && !found) + { + if (fl_track_index[track][head].sector_ID[i] == sector) + found = TRUE; + else + i++; + } + + if (found) + return(i + 1); /* sectors start at 1 */ + else + return(-1); +} + + +static void fl_read_SID(sidname) +char *sidname; +{ + /* + * Attempt to read the sector ID file. If found load the + * information into the track mapping table, else load in + * the standard DOS format. + */ + + FILE *fptr = NULL; + double_word cur_position = 0; + int track, head, no_of_sectors, N_format, sector_ID; + char buf[80]; + char sector_nos[80]; + char rest[80]; + int i; + char sidpath[MAXPATHLEN]; + + + if (fptr == NULL) + { + fptr = fopen(BS_DISKETTE_DOS_SID_NAME, "r"); + if (fptr == NULL) + { + printf("Can't open standard DOS sector ID file - %s\n", BS_DISKETTE_DOS_SID_NAME); + return; + } + } + + while(fgets(buf,80,fptr) != NULL) + { + if (buf[0] != '#') + { + sscanf(buf, "%d %d %d %d %[^\n]", &track, &head, &N_format, + &no_of_sectors, sector_nos); + fl_track_index[track][head].no_of_sectors = no_of_sectors; + fl_track_index[track][head].bytes_per_sector = fl_sector_sizes[N_format]; + fl_track_index[track][head].start_position = cur_position; + + for( i = 0; i < no_of_sectors; i++) + { + sscanf(sector_nos, "%d %[^\n]", §or_ID, rest); + fl_track_index[track][head].sector_ID[i] = sector_ID; + strcpy(sector_nos, rest); + } + + cur_position += (fl_track_index[track][head].bytes_per_sector * no_of_sectors); + } + } + + fclose(fptr); +} +#endif /* VFLOPPY */ diff --git a/private/mvdm/softpc.new/host/src/nt_vga.c b/private/mvdm/softpc.new/host/src/nt_vga.c new file mode 100644 index 000000000..a5c97c34f --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_vga.c @@ -0,0 +1,2188 @@ +/* + * SoftPC Revision 3.0 + * + * Title : Win32 VGA Graphics Module + * + * Description : + * + * This modules contain the Win32 specific functions required + * to support the VGA emulation. + * + * Author : Jerry Sexton (based on X_vga.c) + * + * Notes : + * + */ + +#include <windows.h> +#include "insignia.h" +#include "host_def.h" + +#include "xt.h" +#include "gvi.h" +#include "gmi.h" +#include "gfx_upd.h" +#include <stdio.h> +#include "trace.h" +#include "debug.h" +#include "egagraph.h" +#include "egacpu.h" +#include "egaports.h" +#include "host_rrr.h" +#include "conapi.h" + +#include "nt_graph.h" + +#ifdef MONITOR +#include <ntddvdeo.h> +#include "nt_fulsc.h" +#endif /* MONITOR */ + +IMPORT int DisplayErrorTerm(int, DWORD, char *, int); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Initialise VGA hi res graphics ::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_init_vga_hi_graph() +{ + sub_note_trace0(EGA_HOST_VERBOSE, "nt_init_vga_hi_graph"); + + /* Set up the number of bits per pixel for this mode. */ + sc.BitsPerPixel = VGA_BITS_PER_PIXEL; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::: Paint function (256 colour mode PC 320x200. SoftPC 640x400.):::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_graph_std(int offset, int screen_x, int screen_y, + int width, int height ) +{ + register unsigned short *dest_ptr; + register unsigned short *ref_dest_ptr; + register unsigned char *data_ptr; + register unsigned char *ref_data_ptr; + register int local_height; + register int i, temp, bpl, shorts_per_scanline; + int max_width = sc.PC_W_Width >> 1, + max_height = sc.PC_W_Height >> 1; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_graph_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + /* + * Build up the bitmap: each PC pixel is stored in video memory as one + * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square + * block of 4 host pixels. + */ + bpl = get_bytes_per_line(); + shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + local_height = height; + ref_data_ptr = &EGA_plane0123[offset]; + ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * shorts_per_scanline + screen_x; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up the bitmap. */ + do + { + dest_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for( i = 0; i < width; i++ ) + { + temp = *data_ptr++; + *(dest_ptr + shorts_per_scanline) = *dest_ptr = + (unsigned short)((temp << 8) | temp); + dest_ptr++; + } + ref_dest_ptr += 2 * shorts_per_scanline; + ref_data_ptr += bpl; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 1; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 1) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode PC 320x200. SoftPC 640x400.) on big screen*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + register unsigned short *dest_ptr; + register unsigned short *ref_dest_ptr; + register unsigned char *data_ptr; + register unsigned char *ref_data_ptr; + register int local_height; + register int i; + register int temp1; + register int temp2; + register int half_width; + register int bpl; + int shorts_per_scanline; + int max_width = UNSCALE(sc.PC_W_Width) >> 1, + max_height = UNSCALE(sc.PC_W_Height) >> 1; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_graph_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + bpl = get_bytes_per_line(); + shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + local_height = height; + ref_data_ptr = &EGA_plane0123[offset]; + ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * shorts_per_scanline + + SCALE(screen_x); + half_width = width >> 1; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + dest_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for( i = 0; i < half_width; i++ ) + { + temp1 = *data_ptr++; + temp2 = *data_ptr++; + + *(dest_ptr + 2 * shorts_per_scanline) = + *(dest_ptr + shorts_per_scanline) = + *dest_ptr = (unsigned short) ((temp1 << 8) | temp1); + + *(dest_ptr + (2 * shorts_per_scanline) + 1) = + *(dest_ptr + shorts_per_scanline + 1) = +#ifdef BIGEND + *(dest_ptr + 1) = (unsigned short) ((temp1 << 8) | temp2); +#endif /* BIGEND */ +#ifdef LITTLEND + *(dest_ptr + 1) = (unsigned short) ((temp2 << 8) | temp1); +#endif /* LITTLEND */ + + *(dest_ptr + (2 * shorts_per_scanline) + 2) = + *(dest_ptr + shorts_per_scanline + 2) = + *(dest_ptr + 2) = (unsigned short) ((temp2 << 8) | temp2); + + dest_ptr += 3; + } + + ref_dest_ptr += 3 * shorts_per_scanline; + ref_data_ptr += bpl; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 1); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 1) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*: Paint function (256 colour mode PC 320x200. SoftPC 1280x800.) on huge :*/ +/*: screen. :*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +#ifdef BIGWIN + unsigned char *dest_ptr; + unsigned char *line_ptr; + unsigned char *ref_dest_ptr; + unsigned char *data_ptr; + unsigned char *ref_data_ptr; + int local_height; + int i; + byte temp; + int bpl; + int max_width = UNSCALE(sc.PC_W_Width) >> 1, + max_height = UNSCALE(sc.PC_W_Height) >> 1; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_graph_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + local_height = height; + ref_data_ptr = &EGA_plane0123[offset]; + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y << 1) * bpl + + SCALE(screen_x << 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + line_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for(i = 0; i < width; i++) + { + dest_ptr = line_ptr; + temp = *data_ptr++; + + /* line 1 */ + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr = temp; + + dest_ptr = line_ptr + bpl; + + /* line 2 */ + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr = temp; + + dest_ptr = line_ptr + 2 * bpl; + + /* line 3 */ + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr = temp; + + dest_ptr = line_ptr + 3 * bpl; + + /* line 4 */ + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr++ = temp; + *dest_ptr = temp; + + line_ptr += 4; + } + + ref_dest_ptr += FOUR_SCANLINES * bpl; + ref_data_ptr += 320; + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 1); + rect.Top = SCALE(screen_y << 1); + rect.Right = rect.Left + SCALE(width << 1) - 1; + rect.Bottom = rect.Top + SCALE(height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +#endif /* BIGWIN */ +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode PC 320x200. SoftPC 640x400.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + +void nt_vga_med_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG *p0, + *ref_p0, + *dest_ptr, + *ref_dest_ptr, + data; + UTINY data0, + data1, + data2, + data3; + int local_height, + i, + longs_per_scanline; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_med_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* This mode doubles vertically so, multiply vertical parameters by 2. */ + screen_y <<= 1; + height <<= 1; + + /* If the image is completely outside the display area do nothing. */ + if (((screen_x << 3) >= sc.PC_W_Width) || (screen_y >= sc.PC_W_Height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_graph_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (((screen_x + width) << 3) > sc.PC_W_Width) + width = (sc.PC_W_Width >> 3) - screen_x; + if (screen_y + height > sc.PC_W_Height) + height = sc.PC_W_Height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height >> 1; + + /* Get pointer to video memory. */ + ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + screen_y * longs_per_scanline + (screen_x << 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for(i = 0; i < width; i++) + { + + /* + * Get data and output to screen buffer. NOTE little endian + * dependent code. + */ + data = *p0++; + data0 = (UTINY) (data & 0xff); + data1 = (UTINY) ((data >> 8) & 0xff); + data2 = (UTINY) ((data >> 16) & 0xff); + data3 = (UTINY) (data >> 24); + + *(dest_ptr + longs_per_scanline) = *dest_ptr = + (data1 << 24) | (data1 << 16) | (data0 << 8) | data0; + dest_ptr++; + *(dest_ptr + longs_per_scanline) = *dest_ptr = + (data3 << 24) | (data3 << 16) | (data2 << 8) | data2; + dest_ptr++; + } + + ref_dest_ptr += 2 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 3; + rect.Top = screen_y; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode PC 320x200. SoftPC 960x600.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + +void nt_vga_med_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG *p0, + *ref_p0, + *dest_ptr, + *ref_dest_ptr, + data; + UTINY data0, + data1, + data2, + data3; + int local_height, + i, + longs_per_scanline, + max_width = UNSCALE(sc.PC_W_Width) >> 3, + max_height = UNSCALE(sc.PC_W_Height); + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_med_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* This mode doubles vertically so, multiply vertical parameters by 2. */ + screen_y <<= 1; + height <<= 1; + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_graph_big() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height >> 1; + + /* Get pointer to video memory. */ + ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y) * longs_per_scanline + SCALE(screen_x << 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for(i = 0; i < width; i++) + { + + /* + * Get data and output to screen buffer. NOTE little endian + * dependent code. + */ + data = *p0++; + data0 = (UTINY) (data & 0xff); + data1 = (UTINY) ((data >> 8) & 0xff); + data2 = (UTINY) ((data >> 16) & 0xff); + data3 = (UTINY) (data >> 24); + + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data1 << 24) | (data0 << 16) | (data0 << 8) | data0; + dest_ptr++; + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data2 << 24) | (data2 << 16) | (data1 << 8) | data1; + dest_ptr++; + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data3 << 24) | (data3 << 16) | (data3 << 8) | data2; + dest_ptr++; + } + + ref_dest_ptr += 3 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 3); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode PC 320x200. SoftPC 1080x800.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + +void nt_vga_med_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG *p0, + *ref_p0, + *dest_ptr, + *ref_dest_ptr, + data; + UTINY data0, + data1, + data2, + data3; + int local_height, + i, + longs_per_scanline, + max_width = UNSCALE(sc.PC_W_Width) >> 3, + max_height = UNSCALE(sc.PC_W_Height); + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_med_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* This mode doubles vertically so, multiply vertical parameters by 2. */ + screen_y <<= 1; + height <<= 1; + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_graph_huge() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height >> 1; + + /* Get pointer to video memory. */ + ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y) * longs_per_scanline + SCALE(screen_x << 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for(i = 0; i < width; i++) + { + + /* + * Get data and output to screen buffer. NOTE little endian + * dependent code. + */ + data = *p0++; + data0 = (UTINY) (data & 0xff); + data1 = (UTINY) ((data >> 8) & 0xff); + data2 = (UTINY) ((data >> 16) & 0xff); + data3 = (UTINY) (data >> 24); + + *(dest_ptr + 3 * longs_per_scanline) = + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data0 << 24) | (data0 << 16) | (data0 << 8) | data0; + dest_ptr++; + *(dest_ptr + 3 * longs_per_scanline) = + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data1 << 24) | (data1 << 16) | (data1 << 8) | data1; + dest_ptr++; + *(dest_ptr + 3 * longs_per_scanline) = + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data2 << 24) | (data2 << 16) | (data2 << 8) | data2; + dest_ptr++; + *(dest_ptr + 3 * longs_per_scanline) = + *(dest_ptr + 2 * longs_per_scanline) = + *(dest_ptr + longs_per_scanline) = + *dest_ptr = + (data3 << 24) | (data3 << 16) | (data3 << 8) | data3; + dest_ptr++; + } + + ref_dest_ptr += 4 * longs_per_scanline; + ref_p0 += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 3); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode PC 320x400. SoftPC 640x400.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + +void nt_vga_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + unsigned char *p0, + *ref_p0, + *dest_ptr, + *ref_dest_ptr, + data0, + data1, + data2, + data3; + int local_height, + i, + bpl, + max_width = sc.PC_W_Width >> 3; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_hi_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= sc.PC_W_Height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_hi_graph_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > sc.PC_W_Height) + height = sc.PC_W_Height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height; + + /* Get pointer to video memory. */ + ref_p0 = get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bpl + (screen_x << 3); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for(i = 0; i < width; i++) + { + data0 = *p0++; + data1 = *p0++; + data2 = *p0++; + data3 = *p0++; + + *dest_ptr = data0; + *(dest_ptr + 1) = data0; + *(dest_ptr + 2) = data1; + *(dest_ptr + 3) = data1; + *(dest_ptr + 4) = data2; + *(dest_ptr + 5) = data2; + *(dest_ptr + 6) = data3; + *(dest_ptr + 7) = data3; + dest_ptr += 8; + } + + ref_dest_ptr += bpl; + ref_p0 += 4 * get_offset_per_line(); + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 3; + rect.Top = screen_y; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::Paint function (256 colour mode PC 320(360)x400. SoftPC 920(1080)x600)::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ + unsigned char *p0, + *ref_p0, + *dest_ptr, + *nl_dest_ptr, + *ref_dest_ptr, + data0, + data1, + data2, + data3; + int local_height, + draw_height, + local_screen_y, + i, + bpl, + max_width = UNSCALE(sc.PC_W_Width) >> 3, + max_height = UNSCALE(sc.PC_W_Height); + BOOL two_lines; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_hi_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_hi_graph_big() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + /* Get pointer to video memory. */ + ref_p0 = get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + local_screen_y = SCALE(screen_y + 1) - 1; + bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + local_screen_y * bpl + + SCALE(screen_x << 3); + + /* Set up local parameters. */ + local_height = height; + draw_height = 0; + + /* + * 2 lines are output to the SoftPC screen if this is an odd line, 1 line + * if it is even. + */ + two_lines = screen_y & 1 ? FALSE : TRUE; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for( i = 0; i < width; i++ ) + { + data0 = *p0++; + data1 = *p0++; + data2 = *p0++; + data3 = *p0++; + + *dest_ptr = data0; + *(dest_ptr + 1) = data0; + *(dest_ptr + 2) = data0; + *(dest_ptr + 3) = data1; + *(dest_ptr + 4) = data1; + *(dest_ptr + 5) = data1; + *(dest_ptr + 6) = data2; + *(dest_ptr + 7) = data2; + *(dest_ptr + 8) = data2; + *(dest_ptr + 9) = data3; + *(dest_ptr + 10) = data3; + *(dest_ptr + 11) = data3; + + if (two_lines) + { + nl_dest_ptr = dest_ptr + bpl; + + *nl_dest_ptr = data0; + *(nl_dest_ptr + 1) = data0; + *(nl_dest_ptr + 2) = data0; + *(nl_dest_ptr + 3) = data1; + *(nl_dest_ptr + 4) = data1; + *(nl_dest_ptr + 5) = data1; + *(nl_dest_ptr + 6) = data2; + *(nl_dest_ptr + 7) = data2; + *(nl_dest_ptr + 8) = data2; + *(nl_dest_ptr + 9) = data3; + *(nl_dest_ptr + 10) = data3; + *(nl_dest_ptr + 11) = data3; + } + dest_ptr += 12; + } + + if (two_lines) + { + draw_height += 2; + ref_dest_ptr += 2 * bpl; + } + else + { + draw_height++; + ref_dest_ptr += bpl; + } + two_lines = !two_lines; + + ref_p0 += 4 * get_offset_per_line(); + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 3); + rect.Top = local_screen_y; + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + draw_height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::Paint function (256 colour mode PC 320(360)x400. SoftPC 1280(1440)x800::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height ) +{ + unsigned char *p0, + *ref_p0, + *dest_ptr, + *nl_dest_ptr, + *ref_dest_ptr, + data0, + data1, + data2, + data3; + int local_height, + i, + bpl, + max_width = UNSCALE(sc.PC_W_Width) >> 3, + max_height = UNSCALE(sc.PC_W_Height); + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_hi_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if ((screen_x >= max_width) || (screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_hi_graph_huge() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > max_width) + width = max_width - screen_x; + if (screen_y + height > max_height) + height = max_height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height; + + /* Get pointer to video memory. */ + ref_p0 = get_regen_ptr(0, offset << 2); + + /* Get pointer to bitmap. */ + bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y) * bpl + + SCALE(screen_x << 3); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + p0 = ref_p0; + + for(i = 0; i < width; i++) + { + data0 = *p0++; + data1 = *p0++; + data2 = *p0++; + data3 = *p0++; + + nl_dest_ptr = dest_ptr + bpl; + + *dest_ptr = *nl_dest_ptr = data0; + *(dest_ptr + 1) = *(nl_dest_ptr + 1) = data0; + *(dest_ptr + 2) = *(nl_dest_ptr + 2) = data0; + *(dest_ptr + 3) = *(nl_dest_ptr + 3) = data0; + *(dest_ptr + 4) = *(nl_dest_ptr + 4) = data1; + *(dest_ptr + 5) = *(nl_dest_ptr + 5) = data1; + *(dest_ptr + 6) = *(nl_dest_ptr + 6) = data1; + *(dest_ptr + 7) = *(nl_dest_ptr + 7) = data1; + *(dest_ptr + 8) = *(nl_dest_ptr + 8) = data2; + *(dest_ptr + 9) = *(nl_dest_ptr + 9) = data2; + *(dest_ptr + 10) = *(nl_dest_ptr + 10) = data2; + *(dest_ptr + 11) = *(nl_dest_ptr + 11) = data2; + *(dest_ptr + 12) = *(nl_dest_ptr + 12) = data3; + *(dest_ptr + 13) = *(nl_dest_ptr + 13) = data3; + *(dest_ptr + 14) = *(nl_dest_ptr + 14) = data3; + *(dest_ptr + 15) = *(nl_dest_ptr + 15) = data3; + + dest_ptr += 16; + } + + ref_dest_ptr += 2 * bpl; + ref_p0 += 4 * get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x << 3); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(width << 3) - 1; + rect.Bottom = rect.Top + SCALE(height) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::: Paint function (256 colour mode: PC 320x200. SoftPC 640x400 ::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*Paint function (256 colour mode: PC 320x200. SoftPC 960x600) on big screen*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*: Paint function (256 colour mode: PC 320x200. SoftPC 1280x800) on huge :*/ +/*: screen. :*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 640(720)x400) ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + + +void nt_vga_mono_med_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_med_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 920(1080)x600 ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_med_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_med_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode: PC 320(360)x400. SoftPC 1280(1440)x400 ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_med_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_med_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height ); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 640(720)x400) ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/* The data for this mode is split over all four vga planes and is interlaced + 4 way onto the screen. Hence 4 pixels horizontally for every pixel that the + base detects. Pixels are not doubled vertically. */ + + +void nt_vga_mono_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_hi_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 920(1080)x600 ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_hi_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Paint function (256Col mode: PC 320(360)x400. SoftPC 1280(1440)x400 ::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_mono_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_mono_hi_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height ); +} + +#ifdef V7VGA +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + register unsigned char *dest_ptr; + register unsigned char *ref_dest_ptr; + register unsigned char *data_ptr; + register unsigned char *ref_data_ptr; + register int local_height; + register int i; + int bytes_per_line; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_hi_graph_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim Septemver 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>400 || width>640 ){ + assert2( NO, "VDM: nt_v7vga_hi_graph_std() w=%d h=%d", width, height ); + return; + } + + local_height = height; + bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_data_ptr = &EGA_plane0123[offset]; + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bytes_per_line + + screen_x; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + dest_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for(i = 0; i < width; i++) + *dest_ptr++ = *data_ptr++; + + ref_dest_ptr += bytes_per_line; + ref_data_ptr += get_offset_per_line(); + } + while( --local_height ); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x; + rect.Top = screen_y; + rect.Right = rect.Left + width - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*:::::::: SoftPC 960x600, 960x720, 1080x810, 1200x900. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height) +{ + register unsigned char *dest_ptr; + register unsigned char *ref_dest_ptr; + register unsigned char *data_ptr; + register unsigned char *ref_data_ptr; + register int local_height=0; + register int i, temp1, temp2; + register int half_width = width >> 1; + int bytes_per_line; + int local_screen_y; + BOOL two_lines; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_hi_graph_big off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>400 || width>640 ){ + assert2( NO, "VDM: nt_v7vga_hi_graph_big() w=%d h=%d", width, height ); + return; + } + + /* Get pointer to data in EGA_planes. */ + ref_data_ptr = (unsigned char *) &EGA_plane0123[offset] + + (height - 1) * get_offset_per_line(); + + /* + * Get pointer into bitmap, which alternates 2 lines and 1 line so that, + * memory line 0 -> bitmap 0, + * 1 -> 2, + * 2 -> 3, + * 3 -> 5, + * 4 -> 6 etc. + * hence the local_screen_y assignment. + */ + local_screen_y = SCALE(screen_y + 1) - 1; + bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + local_screen_y * bytes_per_line + + SCALE(screen_x); + + /* Decide whether to start with 1 or 2 scanlines. */ + two_lines = screen_y & 1 ? FALSE : TRUE; + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + dest_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for(i = 0; i < half_width; i++) + { + temp1 = *data_ptr++; + temp2 = *data_ptr++; + *dest_ptr = (unsigned char) temp1; + *(dest_ptr+2) = (unsigned char) temp2; + + if (two_lines) + { + *(dest_ptr+1) = (unsigned char) temp1; + *(dest_ptr + bytes_per_line) = (unsigned char) temp1; + *(dest_ptr + bytes_per_line + 1) = (unsigned char) temp2; + *(dest_ptr + bytes_per_line + 2) = (unsigned char) temp2; + } + else + { + *(dest_ptr+1) = (unsigned char) temp2; + } + dest_ptr+=3; + + } + + ref_data_ptr += get_offset_per_line(); + if (two_lines) + { + local_height += 2; + ref_dest_ptr += 2 * bytes_per_line; + } + else + { + local_height++; + ref_dest_ptr += bytes_per_line; + } + two_lines = !two_lines; + } + while(--height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = local_screen_y; + rect.Right = rect.Left + SCALE(width) - 1; + rect.Bottom = rect.Top + local_height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ + register unsigned char *dest_ptr; + register unsigned char *ref_dest_ptr; + register unsigned char *data_ptr; + register unsigned char *ref_data_ptr; + register int local_height; + register int i; + int bytes_per_line; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_hi_graph_huge off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + /* + ** Tim September 92, sanity check parameters, if they're too big + ** it can cause a crash. + */ + if( height>400 || width>640 ){ + assert2( NO, "VDM: nt_v7vga_hi_graph_huge() w=%d h=%d", width, height ); + return; + } + + local_height = height; + bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_data_ptr = &EGA_plane0123[offset]; + ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap + + SCALE(screen_y) * bytes_per_line + + SCALE(screen_x); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + do + { + dest_ptr = ref_dest_ptr; + data_ptr = ref_data_ptr; + + for(i = 0; i < width; i++) + { + *dest_ptr = *(dest_ptr + bytes_per_line) = *data_ptr; + *(dest_ptr + 1) = *(dest_ptr + 1 + bytes_per_line) = *data_ptr++; + dest_ptr += 2; + } + + ref_dest_ptr -= 2 * bytes_per_line; + ref_data_ptr += get_offset_per_line(); + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = SCALE(screen_x); + rect.Top = SCALE(screen_y); + rect.Right = rect.Left + SCALE(width) - 1; + rect.Bottom = rect.Top + SCALE(height) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_mono_hi_graph_std(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_mono_hi_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*:::::::: SoftPC 960x600, 960x720, 1080x810, 1200x900. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_mono_hi_graph_big(int offset, int screen_x, int screen_y, + int width, int height ) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_mono_hi_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height ); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_v7vga_mono_hi_graph_huge(int offset, int screen_x, int screen_y, + int width, int height) +{ +sub_note_trace5(EGA_HOST_VERBOSE, + "nt_v7vga_mono_hi_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n", + offset, screen_x, screen_y, width, height); +} +#endif /* V7VGA */ + +#ifdef MONITOR +/* There are 2 possible formats for the standard 256 colour VGA mode. One (VGA, + * S3, Ultra etc) has shape 1/ below, the other (ET4000, WD) has a packed + * format more like emulation /2. + * The Miniport sets a flag to tell use which format to use. + * + * 1/ uses paint routine nt_vga_frozen_std + * Regen Memory: XYABJKLM + * Plane 0: X...J... + * Plane 1: Y...K... + * Plane 2: A...L... + * Plane 3: B...M... + * (plus a 1 byte skip every 16k). + * + * 2/ uses paint routine nt_vga_frozen_pack_std + * Regen Memory: XYABJKLM + * Plane 0: XJ.. + * Plane 1: YK.. + * Plane 2: AL.. + * Plane 3: BM.. + * + */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::: Frozen paint function (256 colour mode PC 320x200. SoftPC 640x400.):::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + USHORT *dest_ptr, + *ref_dest_ptr; + UTINY *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + ULONG width_loc, + mem_loc, + shorts_per_scanline, + max_width = sc.PC_W_Width >> 1, + max_height = sc.PC_W_Height >> 1; + + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > (int)max_width) + width = max_width - screen_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + rect.Left = screen_x << 1; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 1) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + + + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* + * Build up the bitmap: each PC pixel is stored in video memory as one + * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square + * block of 4 host pixels. + */ + shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + width >>= 2; + ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * shorts_per_scanline + screen_x; + + + /* Set up the plane pointers. */ + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + + /* Build up the bitmap. */ + do + { + dest_ptr = ref_dest_ptr; + ref_dest_ptr += shorts_per_scanline << 1; + mem_loc = offset; + offset += width; + width_loc = width; + + do + { + ULONG PlaneOffset; + USHORT Tmp; + + // + // Doubleword addressing mode... + // + PlaneOffset = ((mem_loc & 0x3fff) << 2) + + ((mem_loc++ & 0x3000) >> 12); + + Tmp = *(plane1_ptr + PlaneOffset); + *dest_ptr = + *(dest_ptr + shorts_per_scanline) = (Tmp << 8) | Tmp; + dest_ptr++; + + Tmp = *(plane2_ptr + PlaneOffset); + *dest_ptr = + *(dest_ptr + shorts_per_scanline) = (Tmp << 8) | Tmp; + dest_ptr++; + + Tmp = *(plane3_ptr + PlaneOffset); + *dest_ptr = + *(dest_ptr + shorts_per_scanline) = (Tmp << 8) | Tmp; + dest_ptr++; + + Tmp = *(plane4_ptr + PlaneOffset); + *dest_ptr = + *(dest_ptr + shorts_per_scanline) = (Tmp << 8) | Tmp; + dest_ptr++; + + } while (--width_loc); + + } while(--height); + + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + RelMutex(sc.ConsoleBufInfo.hMutex); + assert0(NO, "Handled fault in nt_vga_frozen_std. fs switch?"); + return; + } +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Frozen paint function (256 colour mode packed. PC 320x200 SoftPC 640x400.)*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +void nt_vga_frozen_pack_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + USHORT *dest_ptr, + *ref_dest_ptr; + UTINY *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + ULONG local_width, + local_height, + mem_loc, + temp, + bpl, + shorts_per_scanline, + max_width = sc.PC_W_Width >> 1, + max_height = sc.PC_W_Height >> 1; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_frozen_pack_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height ); + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > (int)max_width) + width = max_width - screen_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* + * Build up the bitmap: each PC pixel is stored in video memory as one + * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square + * block of 4 host pixels. + */ + bpl = get_bytes_per_line() >> 2; + shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + local_height = height; + ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * shorts_per_scanline + screen_x; + + /* Set up the plane pointers. */ + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up the bitmap. */ + do + { + dest_ptr = ref_dest_ptr; + mem_loc = offset; + local_width = width >> 2; + + do + { + + temp = *(plane1_ptr + mem_loc); + *(dest_ptr + shorts_per_scanline) = *dest_ptr = + (unsigned short)((temp << 8) | temp); + dest_ptr++; + temp = *(plane2_ptr + mem_loc); + *(dest_ptr + shorts_per_scanline) = *dest_ptr = + (unsigned short)((temp << 8) | temp); + dest_ptr++; + temp = *(plane3_ptr + mem_loc); + *(dest_ptr + shorts_per_scanline) = *dest_ptr = + (unsigned short)((temp << 8) | temp); + dest_ptr++; + temp = *(plane4_ptr + mem_loc); + *(dest_ptr + shorts_per_scanline) = *dest_ptr = + (unsigned short)((temp << 8) | temp); + dest_ptr++; + mem_loc ++; + } + while (--local_width); + ref_dest_ptr += 2 * shorts_per_scanline; + offset += bpl; + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 1; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 1) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_vga_frozen_std. fs switch?"); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Frozen paint function (256 colour mode PC 320x200. SoftPC 640x400.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_med_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + ULONG *dest_ptr, + *ref_dest_ptr, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height >> 1, + bpl, + local_height, + local_width, + longs_per_scanline, + mem_loc; + UTINY data0, + data1, + data2, + data3, + *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_med_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_med_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > (int)max_width) + width = max_width - screen_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* local_height is number of lines in video memory. */ + local_height = height; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* Get pointer to video memory. */ + bpl = get_bytes_per_line(); + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + + /* Get pointer to bitmap. */ + longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap + + (screen_y << 1) * longs_per_scanline + (screen_x << 1); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Munge. */ + do + { + dest_ptr = ref_dest_ptr; + mem_loc = offset; + local_width = width; + + do + { + + /* + * Get data and output to screen buffer. NOTE little endian + * dependent code. + */ + data0 = *(plane1_ptr + mem_loc); + data1 = *(plane2_ptr + mem_loc); + data2 = *(plane3_ptr + mem_loc); + data3 = *(plane4_ptr + mem_loc); + + *(dest_ptr + longs_per_scanline) = *dest_ptr = + (data1 << 24) | (data1 << 16) | (data0 << 8) | data0; + dest_ptr++; + *(dest_ptr + longs_per_scanline) = *dest_ptr = + (data3 << 24) | (data3 << 16) | (data2 << 8) | data2; + dest_ptr++; + mem_loc++; + } + while (--local_width); + + ref_dest_ptr += 2 * longs_per_scanline; + offset += bpl; + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = screen_x << 3; + rect.Top = screen_y << 1; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + (height << 1) - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_vga_med_frozen_std. fs switch?"); + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Hi-res frozen paint func (256 colour mode PC 320x400. SoftPC 640x400.) */ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void nt_vga_hi_frozen_std(int offset, int screen_x, int screen_y, + int width, int height) +{ + UTINY *dest_ptr, + *ref_dest_ptr, + *plane1_ptr, + *plane2_ptr, + *plane3_ptr, + *plane4_ptr; + ULONG local_height, + local_width, + mem_loc, + bytes_per_scanline, + bpl, + max_width = sc.PC_W_Width >> 3, + max_height = sc.PC_W_Height; + SMALL_RECT rect; + + sub_note_trace5(EGA_HOST_VERBOSE, + "nt_vga_hi_frozen_std off=%d x=%d y=%d width=%d height=%d\n", + offset, screen_x, screen_y, width, height); + + /* + ** Tim September 92, bounce call if handle to screen buffer is null. + ** This can happen when VDM session is about to suspend, buffer has + ** been closed, but still get a paint request. + */ + if( sc.ScreenBufHandle == (HANDLE)NULL ){ + assert0( NO, "VDM: rejected paint request due to NULL handle" ); + return; + } + + /* If the image is completely outside the display area do nothing. */ + if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height)) + { + sub_note_trace2(EGA_HOST_VERBOSE, + "VDM: nt_vga_hi_frozen_std() x=%d y=%d", + screen_x, screen_y); + return; + } + + /* + * If image partially overlaps display area clip it so we don't start + * overwriting invalid pieces of memory. + */ + if (screen_x + width > (int)max_width) + width = max_width - screen_x; + if ((ULONG) (screen_y + height) > max_height) + height = max_height - screen_y; + + /* memory involved here liable to be suddenly removed due to fs switch */ + try + { + /* local_height is number of lines in video memory. */ + local_height = height; + + /* Get pointer to bitmap. */ + bpl = get_bytes_per_line(); + bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo); + ref_dest_ptr = (UTINY *) sc.ConsoleBufInfo.lpBitMap + + screen_y * bytes_per_scanline + (screen_x << 3); + + /* Set up the plane pointers. */ + plane1_ptr = GET_OFFSET(Plane1Offset); + plane2_ptr = GET_OFFSET(Plane2Offset); + plane3_ptr = GET_OFFSET(Plane3Offset); + plane4_ptr = GET_OFFSET(Plane4Offset); + + /* Grab the mutex. */ + GrabMutex(sc.ConsoleBufInfo.hMutex); + + /* Build up the bitmap. */ + do + { + dest_ptr = ref_dest_ptr; + mem_loc = offset; + local_width = width; + + do + { + *(dest_ptr + 1) = *dest_ptr = *(plane1_ptr + mem_loc); + dest_ptr += 2; + *(dest_ptr + 1) = *dest_ptr = *(plane2_ptr + mem_loc); + dest_ptr += 2; + *(dest_ptr + 1) = *dest_ptr = *(plane3_ptr + mem_loc); + dest_ptr += 2; + *(dest_ptr + 1) = *dest_ptr = *(plane4_ptr + mem_loc); + dest_ptr += 2; + mem_loc++; + } + while (--local_width); + ref_dest_ptr += bytes_per_scanline; + offset += bpl; + } + while(--local_height); + + /* Release the mutex. */ + RelMutex(sc.ConsoleBufInfo.hMutex); + + /* Display the new image. */ + rect.Left = (screen_x << 3); + rect.Top = screen_y; + rect.Right = rect.Left + (width << 3) - 1; + rect.Bottom = rect.Top + height - 1; + + if( sc.ScreenBufHandle ) + if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect)) + assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x", + GetLastError() ); + } except(EXCEPTION_EXECUTE_HANDLER) + { + assert0(NO, "Handled fault in nt_vga_hi_frozen_std. fs switch?"); + return; + } +} +#endif /* MONITOR */ diff --git a/private/mvdm/softpc.new/host/src/nt_wcom.c b/private/mvdm/softpc.new/host/src/nt_wcom.c new file mode 100644 index 000000000..05d476cf1 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_wcom.c @@ -0,0 +1,438 @@ +#include <windows.h> +#include <conapi.h> +#include "ptypes32.h" +#include "insignia.h" +#include "host_def.h" + +/* + * Author : D.A.Bartlett + * Purpose: + * + * + * Handle UART I/O's under windows + * + * + * + */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#include "xt.h" +#include "rs232.h" +#include "error.h" +#include "config.h" +#include "host_com.h" +#include "host_trc.h" +#include "host_rrr.h" +#include "debug.h" +#include "idetect.h" +#include "nt_com.h" +#include "nt_graph.h" +#include "nt_uis.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::: Global Data */ +GCHfn GetCommHandle; +GCSfn GetCommShadowMSR; + + +/*::::::::::::::::::::::::::::::::::::::::::::: Internal function protocols */ + +#ifndef PROD +void DisplayPortAccessError(int PortOffset, BOOL ReadAccess, BOOL PortOpen); +#endif + +BOOL SetupBaudRate(HANDLE FileHandle, DIVISOR_LATCH divisor_latch); +BOOL SetupLCRData(HANDLE FileHandle, LINE_CONTROL_REG LCR_reg); +BOOL SyncLineSettings(HANDLE FileHandle, DCB *pdcb, + DIVISOR_LATCH *divisor_latch, + LINE_CONTROL_REG *LCR_reg); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: IMPORTS */ + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: UART state */ + +static struct ADAPTER_STATE +{ + DIVISOR_LATCH divisor_latch; + INT_ENABLE_REG int_enable_reg; + INT_ID_REG int_id_reg; + LINE_CONTROL_REG line_control_reg; + MODEM_CONTROL_REG modem_control_reg; + LINE_STATUS_REG line_status_reg; + MODEM_STATUS_REG modem_status_reg; + half_word scratch; /* scratch register */ + +} adapter_state[NUM_SERIAL_PORTS]; + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: WOW inb function */ + +void wow_com_inb(io_addr port, half_word *value) +{ + int adapter = adapter_for_port(port); + struct ADAPTER_STATE *asp = &adapter_state[adapter]; + BOOL Invalid_port_access = FALSE; + HANDLE FileH; + + + /*........................................... Communications port open ? */ + + if (GetCommHandle == NULL) { + com_inb(port,value); + return; + } + + FileH = (HANDLE)(*GetCommHandle)((WORD)adapter); +#ifndef PROD + if( FileH== NULL) + DisplayPortAccessError(port & 0x7, TRUE, FALSE); +#endif + + /*.................................................... Process port read */ + + switch(port & 0x7) + { + //Process read to RX register + case RS232_TX_RX: + + if(asp->line_control_reg.bits.DLAB == 0) + Invalid_port_access = TRUE; + else + { + if(SyncLineSettings(FileH,NULL,&asp->divisor_latch,&asp->line_control_reg)) + *value = (half_word) asp->divisor_latch.byte.LSByte; + else + Invalid_port_access = TRUE; + } + break; + + + //Process IER read + case RS232_IER: + + if(asp->line_control_reg.bits.DLAB == 0) + Invalid_port_access = TRUE; + else + { + if(SyncLineSettings(FileH,NULL,&asp->divisor_latch,&asp->line_control_reg)) + *value = (half_word) asp->divisor_latch.byte.MSByte; + else + Invalid_port_access = TRUE; + } + break; + + + //Process IIR, LSR and MCR reads + case RS232_IIR: + case RS232_LSR: + case RS232_MCR: + + Invalid_port_access = TRUE; + break; + + case RS232_LCR: + + if(SyncLineSettings(FileH,NULL,&asp->divisor_latch,&asp->line_control_reg)) + *value = asp->line_control_reg.all; + else + Invalid_port_access = TRUE; + + break; + + //Process MSR read + case RS232_MSR: + + *value = (half_word) (*GetCommShadowMSR)((WORD)adapter); + break; + + // Process access to Scratch register + case RS232_SCRATCH: + *value = asp->scratch; + break; + } + + /*.......................................... Handle invalid port accesses */ + +#ifndef PROD + if(Invalid_port_access) + DisplayPortAccessError(port & 0x7, TRUE, TRUE); +#endif + + +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::: WOW outb function */ + +void wow_com_outb(io_addr port, half_word value) +{ + int adapter = adapter_for_port(port); + struct ADAPTER_STATE *asp = &adapter_state[adapter]; + BOOL Invalid_port_access = FALSE; + LINE_CONTROL_REG newLCR; + HANDLE FileH; + + /*........................................... Communications port open ? */ + + if (GetCommHandle == NULL) { + com_outb(port,value); + return; + } + + FileH = (HANDLE)(*GetCommHandle)((WORD)adapter); +#ifndef PROD + if(FileH == NULL) + DisplayPortAccessError(port & 0x7, FALSE, FALSE); +#endif + + /*.................................................... Process port write */ + + switch(port & 0x7) + { + //Process write to TX register + case RS232_TX_RX: + + if(asp->line_control_reg.bits.DLAB == 0) + Invalid_port_access = TRUE; + else + asp->divisor_latch.byte.LSByte= value; + + break; + + //Process write to IER register + case RS232_IER: + + if(asp->line_control_reg.bits.DLAB == 0) + Invalid_port_access = TRUE; + else + asp->divisor_latch.byte.MSByte = value; + + break; + + //Proces write to IIR, MCR, LSR amd MSR + + case RS232_IIR: + case RS232_MCR: + case RS232_LSR: + case RS232_MSR: + + Invalid_port_access = TRUE; + break; + + case RS232_LCR: + + newLCR.all = value; + if(asp->line_control_reg.bits.DLAB == 1 && newLCR.bits.DLAB == 0) + { + if(!SetupBaudRate(FileH,asp->divisor_latch)) + Invalid_port_access = TRUE; + } + + if(!Invalid_port_access && !SetupLCRData(FileH,newLCR)) + Invalid_port_access = TRUE; + + asp->line_control_reg.all = newLCR.all; + break; + + //Scratch register write + + case RS232_SCRATCH: + asp->scratch = value; + break; + } + + /*.......................................... Handle invalid port accesses */ + +#ifndef PROD + if(Invalid_port_access) + DisplayPortAccessError(port & 0x7, FALSE, TRUE); +#endif + +} + + +/*:::::::::::::::: Synchronise Baud/Parity/Stop bits/Data bits with real UART */ + +BOOL SyncLineSettings(HANDLE FileHandle, + DCB *pdcb, + DIVISOR_LATCH *divisor_latch, + LINE_CONTROL_REG *LCR_reg ) +{ + DCB dcb; //State of real UART + register DCB *dcb_ptr; + + + //Get current state of the real UART + + if(pdcb == NULL && !GetCommState(FileHandle, &dcb)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + return(FALSE); + } + + dcb_ptr = pdcb ? pdcb : &dcb; + + // Convert BAUD rate to divisor latch setting + divisor_latch->all = (unsigned short)(115200/dcb_ptr->BaudRate); + + //Setup parity value + LCR_reg->bits.parity_enabled = PARITYENABLE_ON; //Default parity on + + switch(dcb_ptr->Parity) + { + case EVENPARITY : + LCR_reg->bits.even_parity = EVENPARITY_EVEN; + break; + + case NOPARITY : + LCR_reg->bits.parity_enabled = PARITYENABLE_OFF; + break; + + case ODDPARITY : + LCR_reg->bits.even_parity = EVENPARITY_ODD; + break; + + case SPACEPARITY: + LCR_reg->bits.stick_parity = PARITY_STICK; + LCR_reg->bits.even_parity = EVENPARITY_EVEN; + break; + + case MARKPARITY : + LCR_reg->bits.stick_parity = PARITY_STICK; + LCR_reg->bits.even_parity = EVENPARITY_ODD; + break; + } + + //Setup stop bits + LCR_reg->bits.no_of_stop_bits = dcb_ptr->StopBits == ONESTOPBIT ? 0 : 1; + + //Setup data byte size + LCR_reg->bits.word_length = dcb_ptr->ByteSize-5; + + return(TRUE); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::: Setup Line control data */ + +BOOL SetupLCRData(HANDLE FileHandle, LINE_CONTROL_REG LCR_reg) +{ + DCB dcb; //State of real UART + + //Get current state of the real UART + + if(!GetCommState(FileHandle, &dcb)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + return(FALSE); + } + + //Setup data bits + dcb.ByteSize = LCR_reg.bits.word_length+5; + + //Setup stop bits + if(LCR_reg.bits.no_of_stop_bits == 0) + dcb.StopBits = LCR_reg.bits.word_length == 0 ? ONE5STOPBITS:TWOSTOPBITS; + else + dcb.StopBits = ONESTOPBIT; + + //Setup parity + if(LCR_reg.bits.parity_enabled == PARITYENABLE_ON) + { + if(LCR_reg.bits.stick_parity == PARITY_STICK) + { + dcb.Parity = LCR_reg.bits.even_parity == EVENPARITY_ODD ? + MARKPARITY : SPACEPARITY; + + } + else + { + dcb.Parity = LCR_reg.bits.even_parity == EVENPARITY_ODD ? + ODDPARITY :EVENPARITY; + } + } + else + dcb.Parity = NOPARITY; + + //Sent the new line setting values to the serial driver + if(!SetCommState(FileHandle, &dcb)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + return(FALSE); + } + + return(TRUE); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::: Set up the baud rate */ + +BOOL SetupBaudRate(HANDLE FileHandle, DIVISOR_LATCH divisor_latch) +{ + DCB dcb; + + //Setup the baud rate + + if(!GetCommState(FileHandle, &dcb)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + return(FALSE); + } + + dcb.BaudRate = divisor_latch.all ? 115200/divisor_latch.all : 115200; + + if(!SetCommState(FileHandle, &dcb)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + return(FALSE); + } + + return(TRUE); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::: Display port access error */ + + +#ifndef PROD +/* + * user warnings are not needed here, return errors and let the + * app handle it. message boxes are also not permitted, because + * it can kill WOW. 20-Feb-1993 Jonle + */ +void DisplayPortAccessError(int PortOffset, BOOL ReadAccess, BOOL PortOpen) +{ + static char *PortInError; + static char ErrorMessage[250]; + int rtn; + + // Identify port in error + + switch(PortOffset) + { + case RS232_TX_RX: PortInError = ReadAccess ? "RX" : "TX" ; break; + case RS232_IER: PortInError = "IER" ; break; + case RS232_IIR: PortInError = "IIR" ; break; + case RS232_MCR: PortInError = "MCR" ; break; + case RS232_LSR: PortInError = "LSR" ; break; + case RS232_MSR: PortInError = "MSR" ; break; + case RS232_LCR: PortInError = "LCR" ; break; + case RS232_SCRATCH: PortInError = "Scratch" ; break; + default: PortInError = "Unidentified"; break; + } + + //Construct Error message + + sprintf(ErrorMessage, "The Application attempted to %s the %s register", + ReadAccess ? "read" : "write", PortInError); + + if(!PortOpen) + strcat(ErrorMessage,", however the comm port has not yet been opened"); + + //Display message box + printf("WOW Communication Port Access Error\n%s\n",ErrorMessage); +} +#endif diff --git a/private/mvdm/softpc.new/host/src/nt_yoda.c b/private/mvdm/softpc.new/host/src/nt_yoda.c new file mode 100644 index 000000000..7689056fb --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_yoda.c @@ -0,0 +1,1200 @@ +#include "insignia.h" +#include "host_def.h" + + + +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + +MODULE NAME : nt_yoda +FILE NAME : nt_yoda.c + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST + NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT EXPRESS + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD. + + +DESIGNER : Wayne Plummer +DATE : 21st July 1989 + +PURPOSE : Provides host specific extensions to YODA + + +The Following External Routines are defined: + 1. host_force_yoda_extensions + 2. host_yoda_check_I_extensions + 3. host_yoda_help_extensions + + +========================================================================= + +AMMENDMENTS : + + Version Date Author Reason + +========================================================================= +*/ + +#ifdef YODA + +/******INCLUDES**********/ +#include <stdio.h> +#include "xt.h" +#include CpuH +#include "hunter.h" +#include "nt_getXX.h" + +/******DEFINES***********/ +#define EXPORT + +/* Get the size of a table. */ +#define sizeoftable(tab) (sizeof(tab)/sizeof(tab[0])) + +/* Different types of CALL instruction. */ +#define CT_IMM 0 +#define CT_EA 1 +#define CT_REG 2 + +/* Mod-rm table flags. */ +#define MR_BX 0x01 +#define MR_BP 0x02 +#define MR_SI 0x04 +#define MR_DI 0x08 +#define MR_D8 0x10 +#define MR_D16 0x20 + +/* Segment defines, correspond to entries in get_seg table. */ +#define NO_OVERRIDE (-1) +#define SEG_ES (0) +#define SEG_CS (1) +#define SEG_SS (2) +#define SEG_DS (3) + +/* Maximum size of the call stack. */ +#define MAX_CALL_STACK 128 + +/******TYPEDEFS**********/ + +/* Effective address call type additional data. */ +typedef struct +{ + word seg; /* The segment of the effective address. */ + word off; /* The offset of the effective address. */ + sys_addr addr; /* 20-bit effective address. */ + IS8 seg_override; /* Segment override if any. */ + IBOOL disp_present; /* Is there a displacement present? */ + word disp; /* The value of the displacement.*/ + IU8 modrm_index; /* Index into mod-rm look-up tables. */ +} CALL_EA_DATA; + +/* Register call type additional data. */ +typedef IU8 CALL_REG_DATA; /* Index into register look-up tables. */ + +/* Data structure which holds call stack entries. */ +typedef struct +{ + IU8 type; /* CALL instruction type one of + CT_IMM - immediate + CT_EA - effective address in mod-rm + CT_REG - register in mod-rm. */ + word cs; /* Code segment of call instruction. */ + word ip; /* Instruction pointer of call instruction. */ + sys_addr inst_addr; /* 20-bit address of call instruction. */ + IU8 nbytes; /* Length of op-code. */ + IU8 opcode[5]; /* Op-code bytes. */ + IBOOL cfar; /* Is it a far CALL? */ + word seg; /* Target segment for CALL. */ + word off; /* Target offset for CALL. */ + word ss; /* Stack segment when call is executed. */ + word sp; /* Stack offset when call is executed. */ + union + { + CALL_EA_DATA ea; /* EA call specific data. */ + CALL_REG_DATA regind; /* Register call specific data. */ + } extra; +} CALL_STACK_ENTRY; + +/******IMPORTS***********/ +extern struct HOST_COM host_com[]; +extern struct HOST_LPT host_lpt[]; +extern char *nt_fgets(char *buffer, int len, void *input_stream); +extern char *nt_gets(char *buffer); +extern int vader; + +/******LOCAL FUNCTIONS********/ +LOCAL int do_ecbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len); +LOCAL int do_dcbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len); +LOCAL int do_pcbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len); +LOCAL void check_stack IPT2(word, ss, word, sp); +LOCAL int check_for_overflow IPT0(); +LOCAL void get_ea_from_modrm IPT4(CALL_STACK_ENTRY *, cs_ptr, + IU8, mod, + IU8, rm, + sys_addr, op_addr); +LOCAL IS8 do_prefixes IPT1(sys_addr *, opcode_ptr); +LOCAL int do_ntsd IPT5(char *, str, char *, com, long, cs, + long, ip, long, len); + +/******LOCAL VARS********/ + +/* Table of host yoda commands. */ +LOCAL struct +{ + char *name; + int (*function) IPT5(char *, str, char *, com, long, cs, + long, ip, long, len); + char *comment; +} host_yoda_command[] = +{ +{ "ecbt", do_ecbt, " - enable call-back-tracing" }, +{ "dcbt", do_dcbt, " - disable call-back-tracing" }, +{ "pcbt", do_pcbt, " - print call-back-trace" }, +{ "ntsd", do_ntsd, " - break to ntsd" } +}; + +/* Variable to enable call-back-tracing. */ +LOCAL IBOOL call_back_tracing_enabled = FALSE; + +/* Mod-rm byte effective address look-up table. */ +LOCAL IU8 EA_table[] = +{ + MR_BX | MR_SI, + MR_BX | MR_DI, + MR_BP | MR_SI, + MR_BP | MR_DI, + MR_SI, + MR_DI, + MR_D16, + MR_BX, + MR_BX | MR_SI | MR_D8, + MR_BX | MR_DI | MR_D8, + MR_BP | MR_SI | MR_D8, + MR_BP | MR_DI | MR_D8, + MR_SI | MR_D8, + MR_DI | MR_D8, + MR_BP | MR_D8, + MR_BX | MR_D8, + MR_BX | MR_SI | MR_D16, + MR_BX | MR_DI | MR_D16, + MR_BP | MR_SI | MR_D16, + MR_BP | MR_DI | MR_D16, + MR_SI | MR_D16, + MR_DI | MR_D16, + MR_BP | MR_D16, + MR_BX | MR_D16 +}; + +/* Mod-rm byte string look-up table. */ +LOCAL CHAR *EA_strings[] = +{ + "[BX + SI]", + "[BX + DI]", + "[BP + SI]", + "[BP + DI]", + "[SI]", + "[DI]", + "[%hX]", + "[BX]", + "[BX + SI + %hX]", + "[BX + DI + %hX]", + "[BP + SI + %hX]", + "[BP + DI + %hX]", + "[SI + %hX]", + "[DI + %hX]", + "[BP + %hX]", + "[BX + %hX]", + "[BX + SI + %hX]", + "[BX + DI + %hX]", + "[BP + SI + %hX]", + "[BP + DI + %hX]", + "[SI + %hX]", + "[DI + %hX]", + "[BP + %hX]", + "[BX + %hX]" +}; + +/* Table of functions corresponding to register rm fields. */ +LOCAL word (*EA_reg_func[])() = +{ + getAX, + getCX, + getDX, + getBX, + getSP, + getBP, + getSI, + getDI +}; + +/* Table of names of register rm fields. */ +LOCAL CHAR *EA_reg_strings[] = +{ + "AX", + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI" +}; + +/* Table of functions for getting segment values. */ +LOCAL word (*get_seg[])() = +{ + getES, + getCS, + getSS, + getDS +}; + +/* Table of segment names. */ +LOCAL CHAR *seg_strings[] = +{ + "ES", + "CS", + "SS", + "DS" +}; + +LOCAL CALL_STACK_ENTRY call_stack[MAX_CALL_STACK]; +LOCAL CALL_STACK_ENTRY *call_next_free = call_stack; + +/******EXPORT VARS*******/ + +#ifndef PROD +#ifdef HUNTER +/*============================================================ + +Function : trap_command. + +Purpose : Writes the current trapper prompt and gets the + menu input. + +input : a pointer to a string for the current trapper prompt + : a pointer to a character to hold the user input. + +returns : nothing. + +=============================================================*/ + +void trap_command(char *str,char *ch) +{ +char inp[80]; + +printf("%s> ",str); +nt_fgets(inp,80,stdin); +sscanf(inp,"%c",ch); +} +#endif /* HUNTER */ + +/* +========================================================================= + +FUNCTION : host_force_yoda_extensions + +PURPOSE : this function is called whenever the main code of + YODA in the base fails to recognise an instruction + in order for host-specific commands to be implemented. + +RETURNED STATUS : + +NOTES : on the SG port no extensions are provided. + +======================================================================= +*/ + +GLOBAL int host_force_yoda_extensions(char *com, long cs, long ip, long len, + char *str) +{ +#ifdef HUNTER +int quit_menus=FALSE; /* some functions need to return to yoda prompt*/ +char c; +char menu[] = "\tTrapper [m]ain menu\n" + "\tTrapper [e]rror menu\n" + "\t[Q]uit\n" + "\t? for this menu\n\n"; +#endif /* HUNTER */ + int i, + retvalue; + +#ifdef HUNTER +/* to get to this menu, the user has to type "trap" at the Yoda prompt */ + +if(!strcmp(com,"trap")) /* test the input string */ + { + printf("\nYODA EXTENSIONS\n\n"); + printf("%s",menu); + do + { + trap_command("trapper",&c); + switch(c) + { + case 'm': + case 'M': + quit_menus = host_do_trapper_main_menu(); + break; + + case 'e': + case 'E': + quit_menus = host_do_trapper_error_menu(); + break; + + case '?': + printf("%s",menu); + break; + + default: + break; + } + } + while(c != 'q' && c != 'Q' && quit_menus == FALSE ); + + } +else + { + /* unpleasing input, so return 1 and back to main Yoda stuff */ + return(1); + } +return(0); +#endif /* HUNTER */ + + /* Check to see if we have got a command in host_yoda_command. */ + retvalue = 1; + for (i = 0; i < sizeoftable(host_yoda_command); i++) + { + if (strcmp(com, host_yoda_command[i].name) == 0) + { + retvalue = (*host_yoda_command[i].function)(str, com, cs, ip, len); + break; + } + } + return(retvalue); +} + +#ifdef HUNTER +/*============================================================ + +Function : host_do_trapper_main_menu + +Purpose : implements the main trapper menu under Yoda. + + +=============================================================*/ + +static int host_do_trapper_main_menu() +{ +int i,quit_menus = FALSE; +char c,str[80],yesno; +USHORT screen_no; +BOOL compare; + +char menu[] = "\t[F]ast forward...\n" + "\t[N]ext screen\n" + "\t[P]rev screen\n" + "\t[S]how screen...\n" + "\t[C]ontinue\n" + "\t[A]bort\n" + "\t[Q]uit\n" + "\t? for this menu\n\n"; + + + +char continu[] = "\n\ntype 'c' at yoda prompt to continue...\n\n"; + + +printf("\nTRAPPER MAIN MENU\n\n"); +printf("%s",menu); + +do + { + trap_command("main",&c); + switch(c) + { + case 'f': /* fast forward */ + case 'F': + { + printf("\n\nEnter the screen number where comparisons will start: "); + nt_fgets(str,80,stdin); + sscanf(str,"%d",&screen_no); + printf("\n\nSkipping screen comparisons up to screen %d\n\n",screen_no); + bh_start_screen(screen_no); + } + break; + + case 'n': /* next screen */ + case 'N': + { + bh_next_screen(); + printf("%s",continu); + quit_menus = TRUE; + } + break; + + case 'p': /* previous screen */ + case 'P': + { + bh_prev_screen(); + printf("%s",continu); + quit_menus = TRUE; + } + break; + + case 's': /* show screen */ + case 'S': + { + printf("\n\nEnter the number of the screen which you want to see: "); + nt_fgets(str,80,stdin); + sscanf(str,"%d",&screen_no); + printf("\n\nDo you want to compare screen %d with one from" + "SoftPC? (y/n): ",screen_no); + nt_fgets(str,80,stdin); + sscanf(str,"%c",&yesno); + if(yesno == 'y' || yesno == 'Y') + compare = TRUE; + else + compare = FALSE; + + bh_show_screen(screen_no,compare); + } + break; + + case 'c': /* continue */ + case 'C': + { + bh_continue(); + printf("%s",continu); + quit_menus = TRUE; + } + break; + + case 'a': /* abort */ + case 'A': + bh_abort(); + break; + + case '?': + printf("%s",menu); + break; + + default: + break; + } + } +while(c != 'q' && c != 'Q' && quit_menus == FALSE); +return(quit_menus); /* match found */ +} + +/*============================================================ + +Function : host_do_trapper_error_menu + +Purpose : implements the trapper error menu under Yoda. + +returns : TRUE if the user has selected a trapper function + which requires softpc to be restarted. + FALSE otherwise. + +=============================================================*/ + +static int host_do_trapper_error_menu() +{ +int i,quit_menus=FALSE; +char c; +char menu[] = "\t[F]lip screen\n" + "\t[N]ext error\n" + "\t[P]rev error\n" + "\t[A]ll errors\n" + "\t[C]lear errors\n" + "\t[Q]uit menu\n" + "\t? for this menu\n\n"; + + +printf("\nTRAPPER ERROR MENU\n\n"); +printf("%s",menu); + +do + { + trap_command("error",&c); + switch(c) + { + case 'f': + case 'F': + bh_flip_screen(); + printf("\n\ntype 'c' at yoda prompt to continue...\n\n"); + quit_menus = TRUE; + break; + + case 'n': + case 'N': + bh_next_error(); + break; + + case 'p': + case 'P': + bh_prev_error(); + break; + + case 'a': + case 'A': + bh_all_errors(); + break; + + case 'c': + case 'C': + bh_wipe_errors(); + break; + + case '?': + printf("%s",menu); + break; + + default: + break; + } + } +while(c != 'q' && c != 'Q' && quit_menus == FALSE); + +if(quit_menus == TRUE) + return(TRUE); /* need to go to the yoda prompt */ +else + return(FALSE); /* don't need to go to the yoda prompt */ +} +#endif /* HUNTER */ + +/* +========================================================================= + +FUNCTION : host_yoda_check_I_extensions + +PURPOSE : this function is called by the YODA check_I code + in order to provide host specific extensions. + +RETURNED STATUS : + +NOTES : on the SG port no extensions are provided. + +======================================================================= +*/ + +GLOBAL void host_yoda_check_I_extensions() +{ + sys_addr addr; + word cs, + ip, + ss, + sp; + IS8 seg_override; + IU8 opcode, + modrm, + mod, + n_field, + rm, + i; + + /* Check to see if call-back-tracing is enabled. */ + if (call_back_tracing_enabled) + { + + /* Check to see if call on top of stack has been popped. */ + ss = getSS(); + sp = getSP(); + check_stack(ss, sp); + + /* Get current op-code. */ + cs = getCS(); + ip = getIP(); + addr = effective_addr(cs, ip); + seg_override = do_prefixes(&addr); + opcode = sas_hw_at_no_check(addr); + + /* Check to see if we have a call-back-trace op-code. */ + switch (opcode) + { + case 0x9a: + + /* 9a = CALLF immediate */ + + /* Check there is room for another entry in call_stack. */ + if (check_for_overflow() == -1) + return; + + /* Fill the stack entry. */ + call_next_free->type = CT_IMM; + call_next_free->cs = cs; + call_next_free->ip = ip; + call_next_free->inst_addr = addr; + call_next_free->nbytes = 5; + call_next_free->cfar = TRUE; + call_next_free->seg = sas_w_at_no_check(addr + 3); + call_next_free->off = sas_w_at_no_check(addr + 1); + + /* Save state of stack. */ + call_next_free->ss = ss; + call_next_free->sp = sp; + + /* Store instruction bytes. */ + for (i = 0; i < 5; i++) + call_next_free->opcode[i] = sas_hw_at_no_check(addr++); + + /* Increment top of stack. */ + call_next_free++; + break; + case 0xe8: + + /* e8 = CALL immediate */ + + /* Check there is room for another entry in call_stack. */ + if (check_for_overflow() == -1) + return; + + /* Fill the stack entry. */ + call_next_free->type = CT_IMM; + call_next_free->cs = cs; + call_next_free->ip = ip; + call_next_free->inst_addr = addr; + call_next_free->nbytes = 3; + call_next_free->cfar = FALSE; + call_next_free->off = ip + (word) 3 + sas_w_at_no_check(addr + 1); + + /* Save state of stack. */ + call_next_free->ss = ss; + call_next_free->sp = sp; + + /* Store instruction bytes. */ + for (i = 0; i < 3; i++) + call_next_free->opcode[i] = sas_hw_at_no_check(addr++); + + /* Increment top of stack. */ + call_next_free++; + break; + case 0xff: + + /* + * ff /2 = CALL + * ff /3 = CALLF + */ + modrm = sas_hw_at_no_check(addr + 1); + n_field = (modrm & 0x38) >> 3; + if ((n_field == 2) || (n_field == 3)) + { + + /* Check there is room for another entry in call_stack. */ + if (check_for_overflow() == -1) + return; + + /* Save CS:IP of call instruction. */ + call_next_free->cs = cs; + call_next_free->ip = ip; + + /* Store opcode address and initialise byte count. */ + call_next_free->inst_addr = addr; + call_next_free->nbytes = 2; + + /* n-field: 2 = near, 3 = far. */ + call_next_free->cfar = n_field & 1; + + /* If mod is 3 we have a register rm otherwise it is EA. */ + mod = (modrm & 0xc0) >> 6; + rm = modrm & 7; + if (mod == 3) + { + if (call_next_free->cfar) + { + + /* Can't have a far pointer in a register. */ + printf("Invalid mod-rm byte after ff op-code.\n"); + vader = 1; + return; + } + else + { + + /* Near pointer contained in register. */ + call_next_free->type = CT_REG; + call_next_free->off = + sas_w_at_no_check((*EA_reg_func[rm])()); + call_next_free->extra.regind = rm; + + /* Save state of stack. */ + call_next_free->ss = ss; + call_next_free->sp = sp; + } + } + else + { + + /* We have an EA type CALL. */ + call_next_free->type = CT_EA; + call_next_free->extra.ea.seg_override = seg_override; + + /* Adjust address and count for segment override. */ + if (seg_override != NO_OVERRIDE) + { + call_next_free->inst_addr--; + call_next_free->nbytes++; + } + + /* Work out EA from mod-rm. */ + get_ea_from_modrm(call_next_free, mod, rm, addr + 2); + + /* Get target segment and offset from EA. */ + if (call_next_free->cfar) + { + call_next_free->seg = + sas_w_at_no_check(call_next_free->extra.ea.addr+2); + + /* Save state of stack. */ + call_next_free->ss = ss; + call_next_free->sp = sp; + } + else + { + + /* Save state of stack. */ + call_next_free->ss = ss; + call_next_free->sp = sp; + } + call_next_free->off = + sas_w_at_no_check(call_next_free->extra.ea.addr); + } + + /* Fill in the op-code bytes. */ + for (i = 0, addr = call_next_free->inst_addr; + i < call_next_free->nbytes; + i++, addr++) + { + call_next_free->opcode[i] = sas_hw_at_no_check(addr); + } + + /* Increment top of stack. */ + call_next_free++; + } + break; + default: + + /* Not a call-back-trace opcode so do nothing. */ + break; + } + } +} + +/* +========================================================================= + +FUNCTION : check_stack + +PURPOSE : Checks to see if the call on the top of the stack has + been popped and if so removes it from the top of the + call stack. + +RETURNED STATUS : void + +NOTES : Originally the call stack was popped on RET instructions + but this did not work when apps did things like POP + followed by JMP. It was therefore decided to check whether + the stack had shrunk past the point where a call's return + address was stored to see if that call had returned. + +======================================================================= +*/ +LOCAL void check_stack IFN2(word, ss, word, sp) +{ + IU32 count = 0; + + /* + * Pop the call stack until we have a call whose return address is still + * on the real stack. + */ + while ((call_next_free > call_stack) && + (ss == (call_next_free - 1)->ss) && + (sp >= (call_next_free - 1)->sp)) + { + call_next_free--; + count++; + } + + /* Complain if more than one call gets popped. */ + if (count > 1) + printf("Call stack warning - %d calls popped at %04x:%04x\n", + count, getCS(), getIP()); +} + +/* +========================================================================= + +FUNCTION : do_prefixes + +PURPOSE : Skips over all prefix op-codes. + +RETURNED STATUS : Segment override if any. + +NOTES : + +======================================================================= +*/ +LOCAL IS8 do_prefixes IFN1(sys_addr *, opcode_ptr) +{ + half_word opcode; + IS8 seg_override = NO_OVERRIDE; + + /* Skip over prefix opcodes. */ + opcode = sas_hw_at_no_check(*opcode_ptr); + while ((opcode == 0xf2) || (opcode == 0xf3) || + (opcode == 0x26) || (opcode == 0x2e) || + (opcode == 0x36) || (opcode == 0x3e)) + { + switch (opcode) + { + case 0x26: + seg_override = SEG_ES; + break; + case 0x2e: + seg_override = SEG_CS; + break; + case 0x36: + seg_override = SEG_SS; + break; + case 0x3e: + seg_override = SEG_DS; + break; + default: + + /* Not sure what f2 and f3 do so do this for the time being. */ + seg_override = NO_OVERRIDE; + break; + } + opcode = sas_hw_at_no_check(++(*opcode_ptr)); + } + + /* (*opcode_ptr) now points at the opcode. */ + return(seg_override); +} + +/* +========================================================================= + +FUNCTION : check_for_overflow + +PURPOSE : Checks to see if the stack has overflowed. + +RETURNED STATUS : -1 on failure, 0 on success. + +NOTES : + +======================================================================= +*/ +LOCAL int check_for_overflow IFN0() +{ + if (call_next_free - call_stack >= MAX_CALL_STACK) + { + printf("Call stack overflow.\n"); + vader = 1; + return(-1); + } + return(0); +} + +/* +========================================================================= + +FUNCTION : get_ea_from_modrm + +PURPOSE : Takes a mod-rm byte and works out the effective + address and the target segment and offset. + +RETURNED STATUS : void + +NOTES : + +======================================================================= +*/ +LOCAL void get_ea_from_modrm IFN4(CALL_STACK_ENTRY *, cs_ptr, + IU8, mod, + IU8, rm, + sys_addr, disp_addr) +{ + IS16 offset = 0, + disp; + IS8 seg, + seg_override = cs_ptr->extra.ea.seg_override; + IU8 flags; + + /* Get index to table from mod-rm byte. */ + cs_ptr->extra.ea.modrm_index = (mod << 3) | rm; + flags = EA_table[cs_ptr->extra.ea.modrm_index]; + + /* Use segment override if there is one otherwise default to DS. */ + seg = (seg_override == NO_OVERRIDE) ? SEG_DS : seg_override; + + /* Add base register value if any. */ + if (flags & MR_BX) + offset += getBX(); + else if (flags & MR_BP) + { + offset += getBP(); + if (seg_override == NO_OVERRIDE) + seg = SEG_SS; + } + + /* Add index register value if any. */ + if (flags & MR_SI) + offset += getSI(); + else if (flags & MR_DI) + offset += getDI(); + + /* Add displacement if any. */ + if (flags & MR_D16) + { + cs_ptr->nbytes += 2; + cs_ptr->extra.ea.disp_present = TRUE; + cs_ptr->extra.ea.disp = (IS16) sas_w_at_no_check(disp_addr); + offset += cs_ptr->extra.ea.disp; + } + else if (flags & MR_D8) + { + cs_ptr->nbytes++; + cs_ptr->extra.ea.disp_present = TRUE; + cs_ptr->extra.ea.disp = (IS16) ((IS8) sas_hw_at_no_check(disp_addr)); + offset += cs_ptr->extra.ea.disp; + } + else + cs_ptr->extra.ea.disp_present = FALSE; + + /* Store segment and offset of return address. */ + cs_ptr->extra.ea.seg = (*get_seg[seg])(); + cs_ptr->extra.ea.off = (word) offset; + cs_ptr->extra.ea.addr = effective_addr(cs_ptr->extra.ea.seg, + cs_ptr->extra.ea.off); +} + +/* +========================================================================= + +FUNCTION : host_yoda_help_extensions + +PURPOSE : this function is called whenever the user asks for + YODA help to describe the host specific extensions provided + above. + +RETURNED STATUS : + +NOTES : on the SG port no extensions are provided. + +======================================================================= +*/ + +GLOBAL int host_yoda_help_extensions() +{ + int i; + + /* Print out the command and comment fields of host_yoda_command. */ + for(i = 0; i < sizeoftable(host_yoda_command); i++) + { + if (host_yoda_command[i].comment == NULL) + continue; + printf("%14s %s\n", + host_yoda_command[i].name, + host_yoda_command[i].comment); + } +} + +/* +========================================================================= + +FUNCTION : do_ecbt + +PURPOSE : this function enables call-back-tracing. + +RETURNED STATUS : 0 for success, 1 for failure + +NOTES : + +======================================================================= +*/ +LOCAL int do_ecbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len) +{ + + /* Enable call-back-tracing if it is currently disabled. */ + if (!call_back_tracing_enabled) + { + printf("Call back tracing enabled.\n"); + call_back_tracing_enabled = TRUE; + } + return(0); +} + +/* +========================================================================= + +FUNCTION : do_dcbt + +PURPOSE : this function disables call-back-tracing. + +RETURNED STATUS : 0 for success, 1 for failure + +NOTES : + +======================================================================= +*/ +LOCAL int do_dcbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len) +{ + + /* Disable call-back-tracing if it is currently enabled. */ + if (call_back_tracing_enabled) + { + + /* Disable tracing. */ + printf("Call back tracing disabled.\n"); + call_back_tracing_enabled = FALSE; + + /* Reset the stack. */ + call_next_free = call_stack; + } + return(0); +} + +/* +========================================================================= + +FUNCTION : do_pcbt + +PURPOSE : this function prints the call-back-trace stack. + +RETURNED STATUS : 0 for success, 1 for failure + +NOTES : + +======================================================================= +*/ +LOCAL int do_pcbt IPT5(char *, str, char *, com, long, cs, + long, ip, long, len) +{ + IU8 *opcode, + i; + CALL_STACK_ENTRY *cs_ptr; + + /* Print out the current call-back-trace stack. */ + for (cs_ptr = call_stack; cs_ptr < call_next_free; cs_ptr++) + { + + /* Print address and op-code. */ + printf("%04X:%04X", cs_ptr->cs, cs_ptr->ip); + opcode = cs_ptr->opcode; + for (i = 0; i < cs_ptr->nbytes; i++) + printf(" %02X", *opcode++); + + /* Print mnemonic. */ + printf("\tCALL"); + if (cs_ptr->cfar) + printf("F"); + printf("\t"); + + /* Print parameters. */ + switch (cs_ptr->type) + { + case CT_IMM: + + /* Immediate. */ + if (cs_ptr->cfar) + printf("%04X:", cs_ptr->seg); + printf("%04X", cs_ptr->off); + break; + case CT_EA: + + /* Effective address. */ + if (cs_ptr->cfar) + printf("d"); + printf("word ptr "); + + /* Print override if there is one. */ + if (cs_ptr->extra.ea.seg_override != NO_OVERRIDE) + printf("%s:", seg_strings[cs_ptr->extra.ea.seg_override]); + + /* Print parameters. */ + if (cs_ptr->extra.ea.disp_present) + printf(EA_strings[cs_ptr->extra.ea.modrm_index], + cs_ptr->extra.ea.disp); + else + printf(EA_strings[cs_ptr->extra.ea.modrm_index]); + + /* Print effective address. */ + printf("\t(%04X:%04X\t", + cs_ptr->extra.ea.seg, + cs_ptr->extra.ea.off); + + /* Print contents of effective address. */ + if (cs_ptr->cfar) + printf("%04X:", cs_ptr->seg); + printf("%04X)", cs_ptr->off); + break; + case CT_REG: + + /* Print parameter and target address. */ + printf(EA_reg_strings[cs_ptr->extra.regind]); + printf("\t(%04X)", cs_ptr->off); + break; + default: + break; + } + printf("\n"); + } + + /* Return success. */ + return(0); +} + +GLOBAL CHAR *host_get_287_reg_as_string IFN1(int, reg_no) +{ + double reg; + SAVED char regstr[30]; +#ifdef CPU_40_STYLE + strcpy(regstr, "STUBBED get_287_reg"); +#else + IMPORT double get_287_reg_as_double(int); + + reg = get_287_reg_as_double(reg_no); + sprintf(regstr, "%g", reg); +#endif /* CPU_40_STYLE */ + return(®str[0]); +} + +/* +========================================================================= + +FUNCTION : do_ntsd + +PURPOSE : this function forces a break back to ntsd + +RETURNED STATUS : 0 for success, 1 for failure + +NOTES : + +======================================================================= +*/ +LOCAL int do_ntsd IPT5(char *, str, char *, com, long, cs, + long, ip, long, len) +{ + UNUSED(str); + UNUSED(com); + UNUSED(cs); + UNUSED(ip); + UNUSED(len); + DebugBreak(); + return(0); +} + +#endif /* ndef PROD */ + +#endif /* YODA */ + +/* This stub exported as called from main() */ +void host_set_yoda_ints() +{ +} diff --git a/private/mvdm/softpc.new/host/src/sim32.c b/private/mvdm/softpc.new/host/src/sim32.c new file mode 100644 index 000000000..5bcfcf37d --- /dev/null +++ b/private/mvdm/softpc.new/host/src/sim32.c @@ -0,0 +1,462 @@ +/* + * sim32.c - Sim32 for Microsoft NT SoftPC. + * + * Ade Brownlow + * Wed Jun 5 91 + * + * %W% %G% (c) Insignia Solutions 1991 + * + * This module provides the Microsoft sim32 interface with the additional sas + * functionality and some host sas routines. We also provide cpu idling facilities. + * + * This module in effect provides (along with the cpu) what Microsoft term as the IEU - + * see documentation. + */ + +#ifdef SIM32 + +#ifdef CPU_40_STYLE +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#endif /* CPU_40_STYLE */ + +#include <windows.h> +#include "insignia.h" +#include "host_def.h" + +#include <stdlib.h> +#include <stdio.h> +#include "xt.h" +#include "sim32.h" +#include "sas.h" +#include "gmi.h" +#include "ckmalloc.h" +#include CpuH + + +#ifdef CPU_40_STYLE +#include "nt_mem.h" +#endif /* CPU_40_STYLE */ + +/********************************************************/ +/* IMPORTS & EXPORTS */ + +/* Sas/gmi Sim32 crossovers */ +GLOBAL BOOL Sim32FlushVDMPointer (double_word, word, UTINY *, BOOL); +GLOBAL BOOL Sim32FreeVDMPointer (double_word, word, UTINY *, BOOL); +GLOBAL BOOL Sim32GetVDMMemory (double_word, word, UTINY *, BOOL); +GLOBAL BOOL Sim32SetVDMMemory (double_word, word, UTINY *, BOOL); +GLOBAL sys_addr sim32_effective_addr (double_word, BOOL); + +GLOBAL UTINY *sas_alter_size(sys_addr); +GLOBAL UTINY *host_sas_init(sys_addr); +GLOBAL UTINY *host_sas_term(void); + +/* Microsoft sas extensions */ +GLOBAL IMEMBLOCK *sas_mem_map (void); +GLOBAL void sas_clear_map(void); + +IMPORT ULONG Sas_wrap_mask; + + + +#ifndef MONITOR +// +// Pointer to a scratch video buffer. Updated by sim32 routines +// when intel video addr is requested. + +IU8 *ScratchVideoBuffer = 0; +#define VIDEO_REGEN_START 0xa0000 +#define VIDEO_REGEN_END 0xbffff +#define VID_BUFF_SIZE 0x20000 + + +#define IsVideoMemory(LinAddr) \ + ((LinAddr) >= VIDEO_REGEN_START && (LinAddr) <= VIDEO_REGEN_END) + + +IU8 *GetVideoMemory(ULONG iaddr) +{ + + // + // If there isn't a video scratch buffer, allocate one. + // This will stick around until ntvdm terminates. Could be + // optimized to free the buffer when not in use. + // + if (!ScratchVideoBuffer) { + ScratchVideoBuffer = malloc(VID_BUFF_SIZE); + if (!ScratchVideoBuffer) { + return NULL; + } + } + + // + // We could do this more efficiently, by only copying + // minimum area needed, but then we need to keep track of + // what to update on the flush and do ref counting. + // Since video memory access by host code is rare + // (only seen in demWrite\demRead so far) be simple minded. + // + sas_loads (VIDEO_REGEN_START, + ScratchVideoBuffer, + VID_BUFF_SIZE + ); + + return ScratchVideoBuffer + (iaddr - VIDEO_REGEN_START); +} + + +BOOL SetVideoMemory(ULONG iaddr) +{ + ULONG VideoOffset = iaddr - VIDEO_REGEN_START; + + if (!ScratchVideoBuffer) { + return FALSE; + } + + sas_stores(iaddr, + ScratchVideoBuffer + VideoOffset, + VID_BUFF_SIZE - VideoOffset + ); + + return TRUE; +} + +#endif + + + +/********************************************************/ +/* MACROS */ +/* macro to convert the supplied address to intel address */ +#define convert_addr(a,b,c,d) \ + { \ + if ((a = sim32_effective_addr (b,c)) == (sys_addr)-1)\ + {\ + return (d);\ + }\ + } + +/********************************************************/ +/* The actual sim32 interfaces, most of these routines can be more or less mapped directly + * to existing routines in sas or gmi. + * + * WARNING: This routine returns a pointer into M, and + * WILL NOT work for backward M. + */ +UCHAR *Sim32pGetVDMPointer(ULONG addr, UCHAR pm) +{ + sys_addr iaddr; + + if (pm && (addr == 0)) + return(NULL); + + convert_addr (iaddr, addr, pm, NULL); +//STF - need sas_wrap_mask with PE....iaddr &= Sas_wrap_mask; + + if (IsVideoMemory(iaddr)) { + return GetVideoMemory(iaddr); + } + + return (NtGetPtrToLinAddrByte(iaddr)); +} + +/* + * See Sim32pGetVDMPointer + * + * This call must be maintaned as is because it is exported for VDD's + * in product 1.0. + */ +UCHAR *ExpSim32GetVDMPointer IFN3(double_word, addr, double_word, size, UCHAR, pm) +{ + return Sim32pGetVDMPointer(addr, (UCHAR)pm); +} + + +GLOBAL BOOL Sim32FlushVDMPointer IFN4(double_word, addr, word, size, UTINY *, buff, BOOL, pm) +{ + sys_addr iaddr; + convert_addr (iaddr, addr, pm, 0); + +//STF - need sas_wrap_mask with PE....iaddr &= Sas_wrap_mask; + +#ifndef MONITOR + if (IsVideoMemory(iaddr) && !SetVideoMemory(iaddr)) { + return FALSE; + } +#endif //MONITOR + + + sas_overwrite_memory(iaddr, (ULONG)size); + return (TRUE); +} + + +GLOBAL BOOL Sim32FreeVDMPointer IFN4(double_word, addr, word, size, UTINY *, buff, BOOL, pm) +{ + /* we haven't allocated any new memory so always return success */ + return (TRUE); +} + +GLOBAL BOOL Sim32GetVDMMemory IFN4(double_word, addr, word, size, UTINY *, buff, BOOL, pm) +{ + sys_addr iaddr; + convert_addr (iaddr, addr, pm, FALSE); + /* effectivly a sas_loads */ + sas_loads (iaddr, buff, (sys_addr)size); + + /* always return success */ + return (TRUE); +} + +GLOBAL BOOL Sim32SetVDMMemory IFN4(double_word, addr, word, size, UTINY *, buff, BOOL, pm) +{ + sys_addr iaddr; + convert_addr (iaddr, addr, pm, FALSE); + /* effectivly a sas_stores */ + sas_stores (iaddr, buff, (sys_addr)size); + + /* always return success */ + return (TRUE); +} + +/********************************************************/ +/* Support routines for sim32 above */ +GLOBAL sys_addr sim32_effective_addr IFN2(double_word, addr, BOOL, pm) +{ + word seg, off; + double_word descr_addr; + DESCR entry; + + seg = (word)(addr>>16); + off = (word)(addr & 0xffff); + + if (pm == FALSE) + { + return ((double_word)seg << 4) + off; + } + else + { + if ( selector_outside_table(seg, &descr_addr) == 1 ) + { + /* + This should not happen, but is a check the real effective_addr + includes. Return error -1. + */ +#ifndef PROD + printf("NTVDM:sim32:effective addr: Error for addr %#x (seg %#x)\n",addr, seg); + HostDebugBreak(); +#endif + return ((sys_addr)-1); + } + else + { + read_descriptor(descr_addr, &entry); + return entry.base + off; + } + } +} + + +/********************************************************/ +/* Microsoft extensions to sas interface */ +LOCAL IMEMBLOCK *imap_start=NULL, *imap_end=NULL; +GLOBAL IMEMBLOCK *sas_mem_map () +{ + /* produce a memory map for the whole of intel space */ + sys_addr iaddr; + int mem_type; + + if (imap_start) + sas_clear_map(); + + for (iaddr=0; iaddr < Length_of_M_area; iaddr++) + { + mem_type = sas_memory_type (iaddr); + if (!imap_end) + { + /* this is the first record */ + check_malloc (imap_start, 1, IMEMBLOCK); + imap_start->Next = NULL; + imap_end = imap_start; + imap_end->Type = mem_type; + imap_end->StartAddress = iaddr; + continue; + } + if (imap_end->Type != mem_type) + { + /* end of a memory section & start of a new one */ + imap_end->EndAddress = iaddr-1; + check_malloc (imap_end->Next, 1,IMEMBLOCK); + imap_end = imap_end->Next; + imap_end->Next = NULL; + imap_end->Type =mem_type; + imap_end->StartAddress = iaddr; + } + } + /* terminate last record */ + imap_end->EndAddress = iaddr; + return (imap_start); +} + +GLOBAL void sas_clear_map() +{ + IMEMBLOCK *p, *q; + for (p=imap_start; p; p=q) + { + q=p->Next; + free(p); + } + imap_start=imap_end=NULL; +} + +/********************************************************/ +/* Microsoft specific sas stuff (ie host sas) */ + +#define SIXTEENMEG 1024*1024*12 + +LOCAL UTINY *reserve_for_sas = NULL; + +#ifndef CPU_40_STYLE + +LOCAL sys_addr current_sas_size =0; /* A local Length_of_M_area */ + +GLOBAL UTINY *host_sas_init IFN1(sys_addr, size) +{ + UTINY *rez; + DWORD M_plus_type_size; + + /* allocate 16 MEG of virtual memory */ + if (!reserve_for_sas) + { + if (!(reserve_for_sas = (UTINY *)VirtualAlloc ((void *)NULL, SIXTEENMEG, + MEM_RESERVE, PAGE_READWRITE))) + { +#ifndef PROD + printf ("NTVDM:Failed to reserve 16 Meg virtual memory for sas\n"); +#endif + exit (0); + } + } + + /* now commit to our size */ + M_plus_type_size = size + NOWRAP_PROTECTION + + ((size + NOWRAP_PROTECTION) >> 12); + rez = (UTINY *)VirtualAlloc ((void *) reserve_for_sas, + M_plus_type_size, + MEM_COMMIT, + PAGE_READWRITE); + if (rez) + Length_of_M_area = current_sas_size = size; + return (rez); + +} + + +GLOBAL UTINY *host_sas_term() +{ + if (!reserve_for_sas) + return (NULL); + + /* deallocate the reserves */ + VirtualFree (reserve_for_sas, SIXTEENMEG, MEM_RELEASE); + + /* null out reserve pointer */ + reserve_for_sas = NULL; + + Length_of_M_area = current_sas_size = 0; + + return (NULL); +} + +GLOBAL UTINY *sas_alter_size IFN1(sys_addr, new) +{ + UTINY *tmp; + if (!reserve_for_sas) + { +#ifndef PROD + printf ("NTVDM:Sas trying to alter size before reserve setup\n"); +#endif + return (NULL); + } + + /* if we are already at the right size return success */ + if (new == current_sas_size) + { + return (reserve_for_sas); + } + + if (new > current_sas_size) + { + /* move to end of current commited area */ + tmp = reserve_for_sas + current_sas_size; + if (!VirtualAlloc ((void *)tmp, (DWORD)(new - current_sas_size), MEM_COMMIT, + PAGE_READWRITE)) + { + printf ("NTVDM:Virtual Allocate for resize from %d to %d FAILED!\n", + current_sas_size, new); + return (NULL); + } + } + else + { + /* move to the place where sas needs to end */ + tmp = reserve_for_sas + new; + + /* now decommit the unneeded memory */ + if (!VirtualFree ((void *)tmp, (DWORD)(current_sas_size - new), MEM_DECOMMIT)) + { + printf ("NTVDM:Virtual Allocate for resize from %d to %d FAILED!\n", + current_sas_size, new); + return (NULL); + } + } + Length_of_M_area = current_sas_size = new; + return (reserve_for_sas); +} + + + +#else /* CPU_40_STYLE */ + + +// Intel space allocation and deallocation control function for the A4 CPU + +GLOBAL UTINY *host_sas_init IFN1(sys_addr, size) +{ + + /* Initialise memory management system and allocation bottom 1M+64K */ + if(!(Start_of_M_area = InitIntelMemory(size))) + { + /* Initialise function failed, exit */ +#ifndef PROD + printf ("NTVDM:Failed to allocate virtual memory for sas\n"); +#endif + + exit(0); + } + + Length_of_M_area = size; + return(Start_of_M_area); +} + + +GLOBAL UTINY *host_sas_term() +{ + /* Has any Intel memory been allocated ? */ + if(Start_of_M_area) + { + /* Free allocated intel memory and control structures */ + FreeIntelMemory(); + + reserve_for_sas = NULL; /* null out reserve pointer */ + Length_of_M_area = 0; + } + + return(NULL); +} + +#endif /* CPU_40_STYLE */ + +#endif /* SIM32 */ diff --git a/private/mvdm/softpc.new/host/src/sources b/private/mvdm/softpc.new/host/src/sources new file mode 100644 index 000000000..ff583782b --- /dev/null +++ b/private/mvdm/softpc.new/host/src/sources @@ -0,0 +1,111 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + + +MAJORCOMP=spchost +MINORCOMP=src + +TARGETNAME=src + +TARGETPATH=obj + + +NTPROFILEINPUT=yes + +# Pick one of the following and delete the others +TARGETTYPE=LIBRARY + +TARGETLIBS= + +SOFTPC_TREE=$(BASEDIR)\private\mvdm\softpc.new + +INCLUDES=$(SOFTPC_TREE)\host\inc;$(SOFTPC_TREE)\base\inc;$(_NTDRIVE)\nt\private\mvdm\vdd\h;$(_NTDRIVE)\nt\private\mvdm\inc;$(_NTDRIVE)\nt\private\windows\inc;$(_NTDRIVE)\nt\private\inc + +!IF $(ALPHA) +GPSIZE=0 +!ELSE +GPSIZE=0 +!ENDIF + + + +SOURCES= sim32.c \ + cpucstbs.c \ + nt_timer.c \ + nt_ntfun.c \ + nt_msscs.c \ + nt_error.c \ + nt_cga.c \ + nt_ega.c \ + nt_vga.c \ + nt_input.c \ + nt_graph.c \ + nt_hosts.c \ + nt_sound.c \ + nt_bop.c \ + nt_com.c \ + nt_wcom.c \ + nt_rez.c \ + nt_sas.c \ + nt_fdisk.c \ + nt_unix.c \ + nt_keycd.c \ + nt_cpu.c \ + nt_lpt.c \ + nt_yoda.c \ + nt_mouse.c \ + nt_event.c \ + nt_munge.c \ + config.c \ + nt_nls.c \ + copy_fnc.c \ + nt_msscs.c \ + stubs.c \ + nt_pif.c \ + nt_fulsc.c \ + nt_emm.c \ + x86_emm.c \ + nt_eoi.c \ + nt_vdd.c \ + nt_sec.c \ + nt_thred.c \ + nt_det.c \ + nt_umb.c \ + fprt.c \ + nt_rflop.c \ + nt_inthk.c \ + nt_reset.c \ + nt_mem.c + +PPC_SOURCES=nt_aorc.c + +MIPS_SOURCES=$(PPC_SOURCES) + +ALPHA_SOURCES=$(PPC_SOURCES) + +i386_SOURCES= + +!INCLUDE $(SOFTPC_TREE)\obj.vdm\CDEFINE.INC + +UMTYPE=console diff --git a/private/mvdm/softpc.new/host/src/stf_conf.c b/private/mvdm/softpc.new/host/src/stf_conf.c new file mode 100644 index 000000000..ae0932398 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/stf_conf.c @@ -0,0 +1,927 @@ +/* + * SoftPC Revision 3.0 + * + * + * Title : Host dependent configuration panel functions + * + * + * Description : This module forms the host dependant side of the softpc + * configuration system. + * + * + * Author : Wilf Stubs + * + * + * Notes : + * + */ +#include "insignia.h" +#include "host_dfs.h" + +#include <stdio.h> +#include <string.h> + +#include "xt.h" +#include "error.h" +#include "gfi.h" +#include "gmi.h" +#include "gfx_updt.h" +#include "config.h" +#include "rs232.h" +#include "host_lpt.h" +#include "host_cpu.h" +#include "host_com.h" +#include "nt_confg.h" + +/*********** Private definitions ***********************/ + +/* + * Validation routines + */ + +static short validate_c_drive(); +static short validate_d_drive(); +static short validate_com1(); +static short validate_com2(); +static short validate_lpt1(); +static short validate_lpt2(); +#if (NUM_PARALLEL_PORTS>2) +static short validate_lpt3(); +#endif +static short validate_item(); +static short no_validation(); + +/* + * Change action routines + */ + +static short c_drive_change_action(); +static short d_drive_change_action(); +static short no_change_action(); +static short lpt1_change_action(); +static short lpt2_change_action(); +#if (NUM_PARALLEL_PORTS>2) +static short lpt3_change_action(); +#endif +static short com1_change_action(); +static short com2_change_action(); +boolean pc_initiated=FALSE; +char *pc_uif_text; + +boolean use_comments = TRUE; /* Set to true if commenting required. */ + +#define defaults_filename "SoftPC.rez" + +static char *ends[] = +{ + "st","nd","rd","th" +}; + +/* Table definitions for options that take one of n 'value' strings. + * The table is used to look up the string and find what it means + * to the host in this option. + * Look at the tables for more explanation, they're fairly self-explanatory. + */ +name_table bool_values[] = +{ + { "yes", TRUE }, + { "Yes", TRUE }, + { "YES", TRUE }, + { "no", FALSE }, + { "No", FALSE }, + { "NO", FALSE }, + { NULL, 0 } +}; + +name_table gfx_adapter_types[] = +{ + { "HERCULES", HERCULES }, + { "CGA", CGA }, + { "EGA", EGA }, + { "VGA", VGA }, + { NULL, 0 } +}; + +/* The BIG one! This is a decription of each option that the config struct + * must have, and its requirements. Used by config for all sorts of things. + * For a fuller explanation look in the document: + * 'Design Proposal for the New Config System'. + */ + +option_description narrative[] = +{ + { /* FOR EACH OPTION... */ + "HARD_DISK_FILENAME", /* Name */ + C_HARD_DISK1_NAME, /* Host name for option */ + C_STRING_RECORD, /* Option (base) primitive type */ + C_HARD_DISKS, /* Host option commonality type */ + FALSE, /* Option is READ_ONLY if TRUE */ + null_table, /* Pointer to table (null if not needed) */ + TRUE, /* TRUE if default present, FALSE if not */ + "/usr/lib/SoftPC/hard_disk", /* Default value as a string as if in resource file */ + TRUE, /* TRUE if changing the option requires SoftPC reset */ + TRUE, /* TRUE if option may be setup via the UIF */ + DISK_CONFIG, /* Panel 'type' if you have different panels */ + validate_c_drive, /* validation function */ + c_drive_change_action /* function to do changing actions */ + }, + { + "HARD_DISK_FILENAME2", + C_HARD_DISK2_NAME, + C_STRING_RECORD, + C_HARD_DISKS, + FALSE, + null_table, + TRUE, + "", + TRUE, + TRUE, + DISK_CONFIG, + validate_d_drive, + d_drive_change_action + }, + { + "COM_PORT_1", + C_COM1_NAME, + C_STRING_RECORD, + C_SINGULARITY, + FALSE, + null_table, + TRUE, + "", + FALSE, + FALSE, + COMMS_CONFIG, + validate_com1, + com1_change_action + }, + { + "COM_PORT_2", + C_COM2_NAME, + C_STRING_RECORD, + C_SINGULARITY, + FALSE, + null_table, + TRUE, + "", + FALSE, + FALSE, + COMMS_CONFIG, + validate_com2, + com2_change_action + }, + { + "LPT_PORT_1", + C_LPT1_NAME, + C_STRING_RECORD, + C_SINGULARITY, + FALSE, + null_table, + TRUE, + "", + FALSE, + FALSE, + COMMS_CONFIG, + validate_lpt1, + lpt1_change_action + }, + { + "LPT_PORT_2", + C_LPT2_NAME, + C_STRING_RECORD, + C_SINGULARITY, + FALSE, + null_table, + TRUE, + "", + FALSE, + FALSE, + COMMS_CONFIG, + validate_lpt2, + lpt2_change_action + }, + { + "GRAPHICS_ADAPTOR", + C_GFX_ADAPTER, + C_NAME_RECORD, + C_SINGULARITY, + FALSE, + gfx_adapter_types, + TRUE, + "VGA", + TRUE, + TRUE, + DISPLAY_CONFIG, + validate_item, + no_change_action + }, + { + NULL, + 0, + 0, + C_SINGULARITY, + FALSE, + null_table, + FALSE, + NULL, + FALSE, + FALSE, + NON_CONFIG, + no_validation, + no_change_action + } +}; + +/* Runtime variables */ + +struct +{ + boolean mouse_attached; + boolean config_verbose; + boolean npx_enabled; + boolean sound_on; + boolean com_flow_control[2]; + int floppy_state[2]; + int floppy_active_state[2]; + int floppy_capacity[2]; + int hd_cyls[2]; + boolean lptflush1; + boolean lptflush2; + boolean lptflush3; + int flushtime1; + int flushtime2; + int flushtime3; +} runtime_status; + +#define NUM_OPTS ( sizeof(narrative) / sizeof( option_description) ) + +/*********** Imported and exported items *************/ + +extern char *getenv(); +extern char *malloc(); + +/*************** Local Declarations *****************/ + +void host_config_error(); +static char buff[MAXPATHLEN]; +static char buff1[MAXPATHLEN]; +boolean item_in_table(); +static char home_resource[MAXPATHLEN]; +static char sys_resource[MAXPATHLEN]; + +/*********************************************************/ + +short host_runtime_inquire(what) +int what; + +{ + switch(what) + { + case C_MOUSE_ATTACHED: + return( runtime_status.mouse_attached ); + break; + + case C_CONFIG_VERBOSE: + return( runtime_status.config_verbose ); + break; + + case C_NPX_ENABLED: + return( runtime_status.npx_enabled ); + break; + + case C_HD1_CYLS: + return( runtime_status.hd_cyls[0] ); + break; + + case C_HD2_CYLS: + return( runtime_status.hd_cyls[1] ); + break; + + case C_FLOPPY1_STATE: + return( runtime_status.floppy_state[0] ); + break; + + case C_FLOPPY2_STATE: + return( runtime_status.floppy_state[1] ); + break; + + case C_FLOPPY1_ACTIVE_STATE: + return( runtime_status.floppy_active_state[0] ); + break; + + case C_FLOPPY2_ACTIVE_STATE: + return( runtime_status.floppy_active_state[1] ); + break; + + case C_FLOPPY1_CAPACITY: + return( runtime_status.floppy_capacity[0] ); + break; + + case C_FLOPPY_TYPE_CHANGED: + return( runtime_status.floppy_type_changed ); + break; + + case C_FLOPPY2_CAPACITY: + return( runtime_status.floppy_capacity[1] ); + break; + + case C_SOUND_ON: + return( runtime_status.sound_on ); + break; + + case C_REAL_FLOPPY_ALLOC: + return( runtime_status.floppy_state[0] == GFI_REAL_DISKETTE_SERVER || + runtime_status.floppy_state[1] == GFI_REAL_DISKETTE_SERVER ); + break; + + case C_REAL_OR_SLAVE: + return( runtime_status.floppy_A_real ); + break; + + case C_SLAVE_FLOPPY_ALLOC: + return( runtime_status.floppy_state[0] == GFI_SLAVE_SERVER ); + break; + + case C_COM1_FLOW: + return( runtime_status.com_flow_control[0] ); + break; + + case C_COM2_FLOW: + return( runtime_status.com_flow_control[1] ); + break; + + case C_COM3_FLOW: + return( FALSE ); + break; + + case C_COM4_FLOW: + return( FALSE ); + break; + + case C_LPTFLUSH1: + return( runtime_status.lptflush1 ); + break; + + case C_LPTFLUSH2: + return( runtime_status.lptflush2 ); + break; + + case C_LPTFLUSH3: + return( runtime_status.lptflush3 ); + break; + + case C_FLUSHTIME1: + return( runtime_status.flushtime1 ); + break; + + case C_FLUSHTIME2: + return( runtime_status.flushtime2 ); + break; + + case C_FLUSHTIME3: + return( runtime_status.flushtime3 ); + break; + + default: + host_error(EG_OWNUP, ERR_QUIT, "host_runtime_inquire"); + } +} + +void host_runtime_set(what,value) +int what; +int value; +{ + switch(what) + { + case C_MOUSE_ATTACHED: + runtime_status.mouse_attached = value; + break; + + case C_CONFIG_VERBOSE: + runtime_status.config_verbose = value; + break; + + case C_NPX_ENABLED: + runtime_status.npx_enabled = value; + break; + + case C_HD1_CYLS: + runtime_status.hd_cyls[0] = value; + break; + + case C_HD2_CYLS: + runtime_status.hd_cyls[1] = value; + break; + + case C_FLOPPY1_STATE: + runtime_status.floppy_state[0] = value; + break; + + case C_FLOPPY2_STATE: + runtime_status.floppy_state[1] = value; + break; + + case C_FLOPPY1_ACTIVE_STATE: + runtime_status.floppy_active_state[0] = value; + break; + + case C_FLOPPY2_ACTIVE_STATE: + runtime_status.floppy_active_state[1] = value; + break; + + case C_FLOPPY1_CAPACITY: + runtime_status.floppy_capacity[0] = value; + break; + + case C_FLOPPY2_CAPACITY: + runtime_status.floppy_capacity[1] = value; + break; + + case C_FLOPPY_TYPE_CHANGED: + runtime_status.floppy_type_changed = value; + break; + + case C_SOUND_ON: + runtime_status.sound_on = value; + break; + + case C_REAL_OR_SLAVE: + runtime_status.floppy_A_real = value; + break; + + case C_COM1_FLOW: + runtime_status.com_flow_control[0] = value; + break; + + case C_COM2_FLOW: + runtime_status.com_flow_control[1] = value; + break; + + case C_COM3_FLOW: + case C_COM4_FLOW: + break; + + case C_LPTFLUSH1: + runtime_status.lptflush1 =value; + break; + + case C_LPTFLUSH2: + runtime_status.lptflush2 =value; + break; + + case C_LPTFLUSH3: + runtime_status.lptflush3 =value; + break; + + case C_FLUSHTIME1: + runtime_status.flushtime1 =value; + break; + + case C_FLUSHTIME2: + runtime_status.flushtime2 =value; + break; + + case C_FLUSHTIME3: + runtime_status.flushtime3 =value; + break; + + default: + host_error(EG_OWNUP, ERR_QUIT, "host_runtime_set"); + } +} + +void host_runtime_init() +{ + config_values var; + +#ifdef NPX + host_runtime_set(C_NPX_ENABLED,TRUE); +#else + host_runtime_set(C_NPX_ENABLED,FALSE); +#endif + +#ifndef PROD + printf("NPX is %s\n",host_runtime_inquire(C_NPX_ENABLED)? "on.":"off."); +#endif + host_runtime_set(C_FLUSHTIME1, 5); + host_runtime_set(C_FLUSHTIME2, 10); + host_runtime_set(C_FLUSHTIME3, 15); + host_runtime_set(C_MOUSE_ATTACHED,FALSE); + host_runtime_set(C_CONFIG_VERBOSE,TRUE); + host_runtime_set(C_SOUND_ON,FALSE); + host_runtime_set(C_FLOPPY1_STATE,GFI_EMPTY_SERVER); + host_runtime_set(C_FLOPPY2_STATE,GFI_EMPTY_SERVER); + host_runtime_set(C_FLOPPY1_ACTIVE_STATE,GFI_EMPTY_SERVER); + host_runtime_set(C_FLOPPY2_ACTIVE_STATE,GFI_EMPTY_SERVER); + host_runtime_set(C_REAL_OR_SLAVE,FALSE); + host_runtime_set(C_FLOPPY_TYPE_CHANGED,FALSE); +} + +/* + * General host initialisation function. It is called only once on startup + * from 'config()'. It does the following (at the moment): + * + * 1) Makes the 'option' field of the 'config_info' struct pointed to by 'head' * point to all the option 'rules' - that is the 'narrative' structure + * initialised at the start of this file. + * + * 2) Counts up the option rules in 'narrative' and stores the result in the + * 'config_info' struct. + * + * 3) Return the minimum padding length necessary. + * + * 4) Derive the two path:filenames for the resource file. This file may be + * in the user's $HOME directory or in softpc's ROOT directory. Making up + * these strings now saves doing it every time 'config_store()' is called. + */ + +void host_get_config_info(head) +config_description *head; +{ + + char *pp, *getenv(); + option_description *option_p = narrative; + + head->option = narrative; /* Attach 'narrative' */ + head->option_count = NUM_OPTS - 1; + head->min_pad_len = MIN_OPTION_ARG_DIST; + + /* + * get system resource file from standard place + */ + strcpy(sys_resource, ROOT); + + strcat(sys_resource, PATH_SEPARATOR); + strcat(sys_resource, RESOURCE_FILENAME); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::: Try and load database files ::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static boolean try_load_database() +{ + FILE *infile = NULL; + char in_line[MAXPATHLEN]; + char *cp; + char *home, *getenv(); + + /* Keep this the same as system for the moment */ + + sprintf(home_resource,"%s%s%s",ROOT,PATH_SEPARATOR,RESOURCE_FILENAME); + + /*....................................... Attempt to open resource file */ + + if((infile = fopen(home_resource, "r")) == NULL) + return(FALSE); + + /*.................................................. Read resource file */ + + while (fgets(in_line, MAXPATHLEN, infile) != NULL) + { + /*........................................ strip control characters */ + + for(cp = in_line; *cp ; cp++) if(*cp < ' ') *cp = ' '; + + add_resource_node(in_line); + } + + /*............................. Close resource file and get out of here */ + + fclose(infile); + return TRUE; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: Try to load system files ::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +static boolean try_load_sys_file() +{ + FILE *infile = NULL; + char in_line[MAXPATHLEN]; + register char *cp; + + /*................................ Attempt to open system resource file */ + + if((infile = fopen(sys_resource, "r")) == NULL) + return(FALSE); + + /*................................................. read resource file */ + + while (fgets(in_line, MAXPATHLEN, infile) != NULL) + { + /*......................................... strip control characters */ + + for(cp = in_line; *cp ; cp++) + if(*cp < ' ') *cp = ' '; + + add_resource_node(in_line); + } + + /*........................................ close resource file and exit */ + + fclose(infile); + return(TRUE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Read resource file ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +short host_read_resource_file(resource_data *resource) +{ + boolean bad_home=FALSE, bad_sys=FALSE; + + /* Try open users default database failing that, open the system file. */ + + if(bad_home = !try_load_database()) + bad_sys = !try_load_sys_file(); + + if(bad_home && bad_sys) return(EG_ALL_RESOURCE_BAD_R); + + return(bad_home ? EG_BAD_LOCAL_RESOURCE_R : C_CONFIG_OP_OK); +} + +short host_write_resource_file(resource) +resource_data *resource; +{ + +FILE *outfile; +line_node *node; +boolean bad_home=TRUE, bad_sys=FALSE; + + /* Try to open (for writing) a resource file in the users home directory or + failing that, the system one. These two paths are set up once at runtime. */ + + if(home_resource[0] != '\0') + if((outfile = fopen(home_resource, "w")) != NULL) + bad_home = FALSE; + + if(bad_home) + if((outfile = fopen(sys_resource, "w")) == NULL) + bad_sys = TRUE; + + if(bad_home && !bad_sys) + return EG_ALL_RESOURCE_BAD_W; + + else + if(bad_home && bad_sys) + return EG_ALL_RESOURCE_BAD_W; + + node = resource->first; + while(node != NULL) + { + fputs(node->line,outfile); + fputc('\n',outfile); + node = node->next; + } + fclose(outfile); + return(C_CONFIG_OP_OK); + +} + + +/* A host specific extension to config_inquire() to deal with any inquiries + that the base config code doesn't or shouldn't know about. */ + + +void host_inquire_extn(sort,identity,values) +short sort; +int identity; +config_values *values; +{ +} + +static char error_text[300]; +static int error_locus; + +host_error_query_locus(locus,text) +int *locus; +char **text; +{ + *locus = error_locus; + *text = error_text; +} + +host_error_set_locus(text, locus) +char *text; +int locus; +{ + strcpy(error_text, text); + error_locus = locus; +} + +static short no_validation(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ + return(C_CONFIG_OP_OK); +} + +static short validate_c_drive(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will disapear */ + return(C_CONFIG_OP_OK); +} + +static short validate_d_drive(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will disapear */ + return(C_CONFIG_OP_OK); +} + +static short validate_com1(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short validate_com2(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short validate_lpt1(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short validate_lpt2(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short validate_item(value, table, buf) +config_values *value; +name_table table[]; +char *buf; +{ +/* cheat on validation - no table lookup */ + return(C_CONFIG_OP_OK); +} + +boolean item_in_table(val,table) +int val; +name_table table[]; +{ + int n=0; + while(table[n].string != NULL) + if(table[n].value == val) + break; + else + n++; + return( table[n].string == NULL? FALSE : TRUE); +} + +static short no_change_action( value, buf) +config_values *value; +char *buf; +{ + return( C_CONFIG_OP_OK ); +} + +static short c_drive_change_action( value, buf) +config_values *value; +char *buf; +{ + short err; + + fdisk_iodetach (); + fdisk_physdetach(0); + + if (err = fdisk_physattach( 0, value->string)) + strcpy(buf, narrative[C_HARD_DISK1_NAME].option_name); + + fdisk_ioattach (); + + return (err); + +} + +static short d_drive_change_action( value, buf) +config_values *value; +char *buf; +{ + short err; + + fdisk_iodetach (); + fdisk_physdetach(1); + + if (err = fdisk_physattach( 1, value->string)) + strcpy(buf, narrative[C_HARD_DISK2_NAME].option_name); + + fdisk_ioattach (); + + return (err); +} + +static short lpt1_change_action( value, buf) +config_values *value; +char *buf; +{ +#ifdef STUBBED + host_lpt_close(0); + return (host_lpt_open(0, value->string, buf)); +#endif /*STUBBED*/ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short lpt2_change_action( value, buf) +config_values *value; +char *buf; +{ +#ifdef STUBBED + host_lpt_close(1); + return (host_lpt_open(1, value->string, buf)); +#endif /*STUBBED*/ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short com1_change_action( value, buf) +config_values *value; +char *buf; +{ +#ifdef STUBBED + host_com_close(0); + return (host_com_open(0, value->string, buf)); +#endif /*STUBBED*/ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +static short com2_change_action( value, buf) +config_values *value; +char *buf; +{ +#ifdef STUBBED + host_com_close(1); + return (host_com_open(1, value->string, buf)); +#endif /*STUBBED*/ +/* cheat on validation for moment as this will change */ + return(C_CONFIG_OP_OK); +} + +/*********** Floppy and hard disk init ****************/ + +void host_floppy_startup(driveno) +int driveno; +{ + host_floppy_init(driveno, GFI_EMPTY_SERVER ); +} + +void host_hd_startup() +{ + int error; + config_values disk1_name,disk2_name; + + /* Start by getting the C: drive up */ + + fdisk_physdetach(0); + config_inquire(C_INQUIRE_VALUE,C_HARD_DISK1_NAME,&disk1_name); + error = fdisk_physattach(0,disk1_name.string); + if(error) + { + host_error(error, ERR_CONFIG|ERR_QUIT, disk1_name.string); + } + +/* If that went ok, try for D: */ + + config_inquire(C_INQUIRE_VALUE,C_HARD_DISK2_NAME,&disk2_name); + if(!strcmp(disk2_name.string,"")) + return; /* No D: drive! */ + + if(!strcmp(disk2_name.string,disk1_name.string)) + host_error(EG_SAME_HD_FILE, ERR_CONFIG|ERR_QUIT, disk2_name.string); + + error = fdisk_physattach(1,disk2_name.string); + if(error) + host_error(error, ERR_CONFIG|ERR_QUIT, disk2_name.string); + +} + +/* temp hack */ +char *host_get_spc_home() { return("c:\\softpc"); } diff --git a/private/mvdm/softpc.new/host/src/stubs.c b/private/mvdm/softpc.new/host/src/stubs.c new file mode 100644 index 000000000..881b28851 --- /dev/null +++ b/private/mvdm/softpc.new/host/src/stubs.c @@ -0,0 +1,614 @@ +#undef ANSI // until file tidied or better still, lost + +#include <windows.h> +#include <string.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include "host_def.h" +#include "insignia.h" +#include "xt.h" +#include "debug.h" +#include "sas.h" +#include "config.h" +#include "chkmallc.h" + +#ifdef X86GFX +#include "egacpu.h" +#include "egaread.h" +#endif + +#ifdef MONITOR +GLOBAL void sas_loads_to_transbuf IFN3(sys_addr, src, host_addr, dest, sys_addr, len) +{ + sas_loads (src, dest, len); +} + +/* write a string into M */ +GLOBAL void sas_stores_from_transbuf IFN3(sys_addr, dest, host_addr, src, sys_addr, len) +{ + sas_stores (dest, src, len); +} + +GLOBAL host_addr sas_transbuf_address IFN2(sys_addr, dest_intel_addr, sys_addr, length) +{ + UNUSED (dest_intel_addr); + return (sas_scratch_address (length)); +} +#endif + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: log1p */ + +#ifndef MONITOR +GLOBAL double log1p(x) +double x; +{ + return log(1+x); +} + +#endif /* !MONITOR */ + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::: SAS wrapping stubs */ + +#ifdef MONITOR +GLOBAL void npx_reset() +{ + return; +} + +GLOBAL void initialise_npx() +{ + return; +} + +GLOBAL void sas_overwrite_memory IFN2(sys_addr, addr, int, type) +{ + UNUSED(addr); + UNUSED(type); +} + +LOCAL LONG stub_q_ev_count = 0; // holder for below + +/* Monitor controlled code will call quick event code immediately so the + * following needn't be at all accurate. + */ +void host_q_ev_set_count(value) +LONG value; +{ + stub_q_ev_count = value; +} + +LONG host_q_ev_get_count() +{ + return(stub_q_ev_count); +} + +int host_calc_q_ev_inst_for_time(LONG time) +{ + return(time); +} + +#ifndef CPU_40_STYLE +int host_calc_q_ev_time_for_inst(LONG inst) +{ + return(inst); +} +#endif + +////// The following support the major surgery to remove unneeded video stuff + +GLOBAL ULONG Gdp; +GLOBAL half_word bg_col_mask = 0x70; // usually defined in cga.c +GLOBAL READ_STATE read_state; + +ULONG sr_lookup[16] = // Handy array to extract all 4 plane values in one go +{ +#ifdef LITTLEND + 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, + 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, + 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, + 0xffff0000,0xffff00ff,0xffffff00,0xffffffff +#endif +#ifdef BIGEND + 0x00000000,0xff000000,0x00ff0000,0xffff0000, + 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, + 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, + 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff +#endif +}; + +GLOBAL VOID glue_b_write (UTINY *addr, ULONG val) +{ + UNUSED(addr); + UNUSED(val); +} +GLOBAL VOID glue_w_write (UTINY *addr, ULONG val) +{ + UNUSED(addr); + UNUSED(val); +} +GLOBAL VOID glue_b_fill (UTINY *laddr, UTINY *haddr, ULONG val) +{ + UNUSED(laddr); + UNUSED(haddr); + UNUSED(val); +} +GLOBAL VOID glue_w_fill (UTINY *laddr, UTINY *haddr, ULONG val) +{ + UNUSED(laddr); + UNUSED(haddr); + UNUSED(val); +} +GLOBAL VOID glue_b_move(UTINY *laddr, UTINY *haddr, UTINY *src, UTINY src_type ) +{ + UNUSED(laddr); + UNUSED(haddr); + UNUSED(src); + UNUSED(src_type); +} +GLOBAL VOID glue_w_move(UTINY *laddr, UTINY *haddr, UTINY *src ) +{ + UNUSED(laddr); + UNUSED(haddr); + UNUSED(src); +} +GLOBAL VOID glue_b_fwd_move () { } +GLOBAL VOID glue_b_bwd_move () { } +GLOBAL VOID glue_w_fwd_move () { } +GLOBAL VOID glue_w_bwd_move () { } + +GLOBAL VOID _ega_gc_outb_mask(io_addr port, half_word value) +{ + UNUSED(port); + UNUSED(value); +} + +GLOBAL VOID _ega_gc_outb_mask_ff(io_addr port, half_word value) +{ + UNUSED(port); + UNUSED(value); +} + +GLOBAL VOID cga_init() +{ +} + +GLOBAL VOID cga_term() +{ +} + +GLOBAL VOID _simple_mark_lge() +{ +} + +GLOBAL VOID _simple_mark_sml() +{ +} + +GLOBAL int get_ega_switch_setting() +{ + return(0); +} + +GLOBAL VOID ega_read_init() // Do normal inits - ports will do this fully +{ + read_state.mode = 0; + read_state.colour_compare = 0x0f; + read_state.colour_dont_care = 0xf; +} + +GLOBAL VOID ega_read_term() +{ +} + +GLOBAL VOID ega_read_routines_update() +{ +} + +GLOBAL VOID update_shift_count() +{ +} + +GLOBAL VOID ega_write_init() +{ +} + +GLOBAL VOID ega_write_term() +{ +} + +GLOBAL VOID ega_write_routines_update(CHANGE_TYPE reason) +{ + UNUSED(reason); +} + +GLOBAL VOID set_mark_funcs() +{ +} + +GLOBAL ULONG setup_global_data_ptr() +{ + return(0xDefaced); +} + +GLOBAL VOID setup_vga_globals() +{ + check_malloc(EGA_CPU.globals, 1, VGA_GLOBALS); +} + +#endif //MONITOR + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ASSERT CODE */ + + +void _assert(void *exp, void *file, unsigned line) +{ + char linestr[100]; + + OutputDebugString("ASSERT FAILED - "); + OutputDebugString(exp); + OutputDebugString(" "); + OutputDebugString(file); + + sprintf(linestr," (%d)\n",line); + OutputDebugString(linestr); +} + +/*:::::::::::::::::::::::::::: Unix specific string functions ::::::::::::::*/ + +char *index(char *string, int c) +{ + return(strchr(string, c)); +} + +char *rindex(char *string, int c) +{ + return(strrchr(string, c)); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +host_mouse_in_use() +{ +return(FALSE); +} + +void redirector() {} +void reset_delta_data_structures() {} +void set_hfx_severity() {} + +host_check_for_lock() +{ + assert0(NO,"host_check_for_lock stubbed\n"); + return(0); +} + +host_place_lock(int dummy1) +{ + assert0(NO,"host_place_lock stubbed\n"); + return(0); +} + +host_clear_lock(int fd) +{ + assert0(NO,"host_clear_lock stubbed\n"); + return(0); +} + + +int host_com_send_delay_done(int dummy1, int dummy2) +{ + return(0); +} +#ifndef A2CPU +delta_cpu_test_frag() +{ + assert0(NO,"delta_cpu_test_frag stubbed\n"); + return(0); +} + +examine_delta_data_structs(int o, int i) +{ + assert0(NO,"examine_delta_data_structs stubbed\n"); + return(0); +} +code_gen_files_init() +{ + assert0(NO,"code_gen_files_init stubbed\n"); + return(0); +} +decode_files_init() +{ + assert0(NO,"decode_files_init stubbed\n"); + return(0); +} + +#ifdef ALPHA + +// +// temporary change to get Alpha CPU running +// in checked mode. Andy - 13/1/94 +// + +double get_287_reg_as_double(int i) +{ + extern char *GDP; + return(*(double *)(GDP + 0x80 + i * 8)); +} +#endif + +#ifdef CPU_40_STYLE + +GLOBAL BOOL sas_manage_xms IFN3(VOID *,start_addr, ULONG, cb, INT, a_or_f) +{ + printf("sas_manage_xms called(%lx,%lx,%lx)\n",start_addr,cb,a_or_f); + return (TRUE); +} + +#undef sas_loadw +GLOBAL void sas_loadw IFN2(sys_addr, addr, word *, val) +{ + *val = sas_w_at(addr); +} + +GLOBAL void host_sigio_event IPT0() +{ +} + +#endif /* CPU_40_STYLE */ + +#ifndef GENERIC_NPX +#ifndef CPU_40_STYLE +int get_287_sp() +{ + extern char *GDP; + return((int) (*(ULONG *)(GDP + 0x70))/8); +} +word get_287_tag_word() +{ + extern char *GDP; + return((int) *(ULONG *)(GDP + 0x74)); +} +word get_287_control_word() +{ + extern char *GDP; + return((int) *(ULONG *)(GDP + 0x68)); +} +word get_287_status_word() +{ + extern char *GDP; + return((int) *(ULONG *)(GDP + 0x6c)); +} +#endif /* CPU_40_STYLE */ +#endif /* GENERIC_NPX */ +#endif + +int rate_min; +int rate_max; +int compiling; +int rate_delta; +int show_stuff; +int stat_rate; +int compile_off[99]; +int rate_norm; +int cut_off_level; +int max_host_fragment_size; +int delta_err_message[100]; +int last_destination_address; + + +host_flip_real_floppy_ind() +{ + assert0(NO,"host_flip_real_floppy_ind stubbed\n"); + return(0); +} + +#ifndef A2CPU +int haddr_of_src_string; +int INTEL_STATUS; +int R_SI; +int R_DI; +int R_BP; +int R_OPA; +int R_DEF_SS; +int R_OPB; +int R_SP; +int R_DEF_DS; +int R_AX; +int R_BX; +int R_CX; +int R_DX; +int R_IP; +int R_ACT_CS; +int R_ACT_SS; +int R_OPR; +int R_ACT_DS; +int R_ACT_ES; +#endif +int compile_yoda_in; +int m_s_w; +int trap_delay_count = 0, temp_trap_flag = 0; +int cpui; +int sbp; + +host_EOA_hook() +{ + assert0(NO,"host_EOA_hook stubbed\n"); + return(0); +} + +getsdosunit() +{ + assert0(NO,"dispatch_q_event stubbed\n"); + return(1); +} + +#ifdef NOT_IN_USE +host_check_using_host_mouse() +{ + assert0(NO,"host_check_using_host_mouse stubbed\n"); + return(1); +} +host_deinstall_host_mouse() +{ + assert0(NO,"host_deinstall_host_mouse stubbed\n"); + return(1); +} +#endif + +int host_timer_2_frig_factor = 20; + +host_check_read_only_drive() +{ + assert0(NO,"host_check_read_only_drive stubbed\n"); + return(0); +} + +host_lock_drive_and_make_writable() +{ + assert0(NO,"host_lock_drive_and_make_writable stubbed\n"); + return(1); +} + +host_floppy_init() +{ + assert0(NO,"host_floppy_init stubbed\n"); + return(1); +} + +SHORT validate_hfx_drive() +{ + assert0(NO,"host_lpt_valid\n"); + return C_CONFIG_OP_OK; +} + +SHORT host_keymap_valid() +{ + assert0(NO,"host_keymap_valid\n"); + return C_CONFIG_OP_OK; +} + +VOID host_keymap_change() +{ + assert0(NO,"host_keymap_change\n"); +} + +char *host_strerror(int errno) +{ + assert1(NO,"Error : host_strerror (%d)\n",errno); + return("****** again\n"); +} + +int link(void) +{ +return -1; +} + +LOCAL ULONG dummy() +{ + return(0); +} + +GLOBAL ULONG (*clear_v7ptr)() = dummy; +GLOBAL ULONG (*paint_v7ptr)() = dummy; + +GLOBAL ULONG host_speed IFN1(ULONG, temp) +{ +return 10000L; +} + +#ifndef MONITOR + +// allows getIntelRegistersPointer to be exported bt ntvdm.def +getIntelRegistersPointer() +{ + assert0(NO,"getIntelRegistersPointer stubbed\n"); + return(0); +} + +#if 0 +// these two crept into WOW - they are x86 monitor'isms + +word getEIP() +{ + return(c_getIP()); +} + +void setEIP(val) +word val; +{ + c_setIP(val); +} +#endif + +int FlatAddress[1]; +int Ldt[1]; +int VdmTib; +int VdmTibStruct; + +void DispatchInterrupts() +{ +} + +#else //MONITOR + +#ifndef YODA +void check_I() +{ +} + +void force_yoda() +{ + printf("Yoda disabled on x86\n"); +} +#endif //YODA + +#endif //MONITOR + + +#ifndef MONITOR + +// +// davehart 9-Dec-92 HACKHACK +// Build fix -- we export cpu_createthread from ntvdm.exe, +// even though this function from v86\monitor\i386 doesn't +// exist on MIPS. +// +// If we really need to export the function, we may want to +// take the ntoskrnl.src -> obj\i386\ntoskrnl.def approach. +// + +VOID +cpu_createthread( + HANDLE Thread + ) +/*++ + +Routine Description: + + This routine adds a thread to the list of threads that could be executing + in application mode. + +Arguments: + + Thread -- Supplies a thread handle + +Return Value: + + None. + +--*/ +{ +} + +#endif // ndef MONITOR + +#ifndef MONITOR +ULONG CurrentMonitorTeb; +#endif + +void host_note_queue_added() +{ +} diff --git a/private/mvdm/softpc.new/host/src/x86_emm.c b/private/mvdm/softpc.new/host/src/x86_emm.c new file mode 100644 index 000000000..cfb95047c --- /dev/null +++ b/private/mvdm/softpc.new/host/src/x86_emm.c @@ -0,0 +1,948 @@ +/* INSIGNIA MODULE SPECIFICATION + ----------------------------- + +MODULE NAME : 'Lower layer' of Expanded Memory Manager + + THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE + CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST + NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS + AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS INC. + +DESIGNER : Simon Frost +DATE : March '92 + +PURPOSE : NT specific code for EMS LIM rev 4.0 + implementation. + +The Following Routines are defined: + 1. host_initialise_EM() + 2. host_deinitialise_EM() + 3. host_allocate_storage() + 4. host_free_storage() + 5. host_reallocate_storage() + 6. host_map_page() + 7. host_unmap_page() + 8. host_alloc_page() + 9. host_free_page() + 10. host_copy_con_to_con() + 11. host_copy_con_to_EM() + 12. host_copy_EM_to_con() + 13. host_copy_EM_to_EM() + 14. host_exchg_con_to_con() + 15. host_exchg_con_to_EM() + 16. host_exchg_EM_to_EM() + 17. host_get_access_key() + +========================================================================= +*/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> + +#include "insignia.h" +#include "host_def.h" +#include "string.h" +#include "stdlib.h" + +#ifdef LIM +#ifdef MONITOR //x86 specific LIM functions + +#include "xt.h" +#include "emm.h" +#include "sas.h" +#include "host_rrr.h" +#include "debug.h" +#include "umb.h" +#include "host_emm.h" +#include "nt_uis.h" + +/* Global Variables */ + +/* Forward Declarations */ +BOOL hold_lim_page(USHORT segment); +/* find this function in monitor/sas.c */ +extern BOOL HoldEMMBackFillMemory(ULONG Address, ULONG Size); + + +/* Local Variables */ + +LOCAL UTINY *EM_pagemap_address = NULL; /* address of start of pagemap */ + +/* pagemap requires 1 bit per 16K page - i.e. 8 bytes per meg */ +LOCAL UTINY EM_pagemap[8*32]; + +LOCAL VOID *BaseOfLIMMem = NULL; // start of expanded memory +ULONG HolderBlockOffset; // holder block offset + +LOCAL HANDLE LIMSectionHandle; +LOCAL HANDLE processHandle = NULL; + +LOCAL ULONG X86NumRoms = 0; + +#define PAGE_SEG_SIZE 0x400 /* size of page expressed as segment */ + +#define CONFIG_DATA_STRING L"Configuration Data" +#define KEY_VALUE_BUFFER_SIZE 2048 + +#define EMMBASE 0xd0000 +#define EMMTOP 0xe0000 + +#define SECTION_NAME L"\\BaseNamedObjects\\LIMSection" +#define SECTION_NAME_LEN sizeof(SECTION_NAME) + +typedef struct _BIOS_BLOCK { + ULONG PhysicalAddress; + ULONG SizeInByte; +} BIOS_BLOCK; + + +/* +Defines are: + EM_loads(from, to, length), copies length bytes from intel 24 bit + address from, to host 32 bit address to + EM_stores(to, from, length), copies length bytes from host 32 bit + address from to intel 24 bit address to + EM_moves(from, to, length), copies length bytes from intel 24 bit + address from to intel 24 bit address to + EM_memcpy(to, from, length), copies length bytes from host 32 bit + address from to host 32 bit address to +*/ + + +#define EM_loads(from, to, length) memcpy(to, get_byte_addr(from), length) +#define EM_stores(to, from, length) \ + RtlCopyMemory(get_byte_addr(to), from, length) +#define EM_moves(from,to,length) \ + RtlMoveMemory(get_byte_addr(to), get_byte_addr(from), length) +#define EM_memcpy(to, from, length) \ + RtlMoveMemory(to, from, length) + +/* +=========================================================================== + +FUNCTION : host_initialise_EM + +PURPOSE : allocates the area of memory that is used for + expanded memory and sets up an area of memory to be used + for the logical pagemap allocation table. + + +RETURNED STATUS : SUCCESS - memory allocated successfully + FAILURE - unable to allocate required space + +DESCRIPTION : + + +========================================================================= +*/ +int host_initialise_EM(short size) +/* IN short size size of area required in megabytes */ +{ + UTINY *pagemap_ptr; /* temp ptr. to logical pagemap */ + int i; /* loop counter */ + NTSTATUS status; + OBJECT_ATTRIBUTES objAttribs; + LARGE_INTEGER secSize; + ULONG viewSize; + USHORT PageSegment, Pages; + LONG EM_size; + + SAVED UNICODE_STRING LIMSectionName = + { + SECTION_NAME_LEN, + SECTION_NAME_LEN, + SECTION_NAME + }; + + + /* Nobody should call this function with size 0 */ + ASSERT(size != 0); + + EM_pagemap_address = &EM_pagemap[0]; + + /* initialise pagemap to 0's */ + + pagemap_ptr = EM_pagemap_address; + for(i = 0; i < 8*32; i++) + *pagemap_ptr++ = 0; + + EM_size = ((long) size) * 0x100000; + + if (!(processHandle = NtCurrentProcess())) + { + assert0(NO, "host_initialise_EM: cant get process handle"); + return(FAILURE); + } + + // create section for LIM + + /* Fill the fields of the OBJECT_ATTRIBUTES structure. */ + InitializeObjectAttributes(&objAttribs, + NULL, // was &LIMSectionName, but null means private + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Create the section. EMM_PAGE_SIZE for holder page */ + secSize.LowPart = EM_size + EMM_PAGE_SIZE; + secSize.HighPart = 0; + HolderBlockOffset = EM_size; + + // improvement - just reserve & commit as needed... + status = NtCreateSection(&LIMSectionHandle, + SECTION_MAP_WRITE|SECTION_MAP_EXECUTE, + &objAttribs, + &secSize, + PAGE_EXECUTE_READWRITE, + SEC_COMMIT, + NULL); + if (!NT_SUCCESS(status)) + { + assert1(NO, "host_initialise_EM: LIM section creation failed (%x)", status); + return(FAILURE); + } + + /* Map the section to the process' address space. */ + BaseOfLIMMem = NULL; + viewSize = 0; + + status = NtMapViewOfSection(LIMSectionHandle, + processHandle, + (PVOID *) &BaseOfLIMMem, + 0, + 0, + NULL, + &viewSize, + ViewUnmap, + 0, // do we need mem_top_down?? + PAGE_READWRITE); + if (!NT_SUCCESS(status)) + { + assert1(NO, "host_initialise_EM: can't map view of LIM section (%x)", status); + return(FAILURE); + } + + /* acquire page frame addresss space from UMB list */ + if (!GetUMBForEMM()) { + host_deinitialise_EM(); + return FAILURE; + } + + /* attach page to holder so that we won't get killed if applications + * try to touch the page frames without mapping + */ + + for (Pages = get_no_phys_pages(); Pages ; Pages--) { + PageSegment = get_page_seg((unsigned char)(Pages - 1)); + if (PageSegment <= 640 * 1024 / 16) + continue; + if (!hold_lim_page(PageSegment)) + return FAILURE; + + } + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_deinitialise_EM + +PURPOSE : frees the area of memory that was used for + expanded memory and memory used + for the logical pagemap allocation table. + + +RETURNED STATUS : SUCCESS - memory freed successfully + FAILURE - error ocurred in freeing memory + +DESCRIPTION : + + +========================================================================= +*/ +int host_deinitialise_EM() +{ + ULONG len = 0x10000; + NTSTATUS status; + + if (BaseOfLIMMem != NULL) + { + if (processHandle == NULL) + { + //As shutting down anyway then fail silently + return(FAILURE); + } + + // lose section from our memory space + status = NtUnmapViewOfSection(processHandle, BaseOfLIMMem); + if (!NT_SUCCESS(status)) + { + //As shutting down anyway then fail silently + return(FAILURE); + } + + status = NtClose(LIMSectionHandle); // delete section + if (!NT_SUCCESS(status)) + { + //As shutting down anyway then fail silently + return(FAILURE); + } + + return(SUCCESS); + } +} + + + +/* +=========================================================================== + +FUNCTION : host_allocate_storage + +PURPOSE : allocates an area of memory of requested size, to be + used as a general data storage area. The area is + to zeros. + +RETURNED STATUS : storage_ID - (in this case a pointer) + NULL - failure to allocate enough space. + + +DESCRIPTION : returns memory initialised to zeros. + The storage ID returned is a value used to later reference + the storage area allocated. The macro USEBLOCK in + "host_emm.h" is used by the manager routines to convert + this ID into a char pointer + +========================================================================= +*/ +long host_allocate_storage(int no_bytes) +/* IN int no_bytes no. of bytes required */ +{ + // should replace this (?) - dissasembling calloc seems to + // indicate it uses win funx... + return ((long)calloc(1, no_bytes)); +} + + +/* +=========================================================================== + +FUNCTION : host_free_storage + +PURPOSE : frees the area of memory that was used for + data storage + + +RETURNED STATUS : SUCCESS - memory freed successfully + FAILURE - error ocurred in freeing memory + +DESCRIPTION : In this implementation storage_ID is simply a pointer + + +========================================================================= +*/ +int host_free_storage(long storage_ID) +/* IN long storage_ID ptr to area of memory */ +{ + if(storage_ID != (long)NULL) + free((char *)storage_ID); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_reallocate_storage + +PURPOSE : increases the size of memory allocated, maintaining the + contents of the original memory block + + +RETURNED STATUS : storage_ID - memory reallocated successfully + NULL - error ocurred in reallocating memory + +DESCRIPTION : In this implementation storage_ID is simply a pointer + Note the value of storage_ID returned may or may not be the + same as the value given + +========================================================================= +*/ +long host_reallocate_storage(LONG storage_ID, int size, int new_size) +/* + IN +long storage_ID ptr to area of memory +int size original size - not used in this version + new_size new size required +*/ +{ + return((long)realloc((char *)storage_ID, new_size)); +} + + +/* +=========================================================================== + +FUNCTION : hold_lim_page + +PURPOSE : Puts some memory in one of the LIM page gaps in 16 bit + memory. Ensures nothing else in the process gets that + via malloc. + + +RETURNED STATUS : TRUE - mapping OK. + +DESCRIPTION : Mapping achieved by mapping correct page from section into + Intel memory +========================================================================= +*/ +BOOL hold_lim_page(USHORT segment) +/* IN +int page page (0-3) of LIM gap +*/ + +{ + PVOID to; + LARGE_INTEGER sec_offset; + ULONG viewSize; + NTSTATUS status; + + if (BaseOfLIMMem != NULL) + { + to = (PVOID)effective_addr(segment, (word)0); + + sec_offset.LowPart = HolderBlockOffset; + sec_offset.HighPart = 0; + + viewSize = EMM_PAGE_SIZE; + + status = NtMapViewOfSection(LIMSectionHandle, + processHandle, + &to, + 0, + EMM_PAGE_SIZE, + &sec_offset, + &viewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_EXECUTE_READWRITE); + if (!NT_SUCCESS(status)) + { + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + return(FALSE); + } + return(TRUE); + } + return(FALSE); +} + + +/* +=========================================================================== + +FUNCTION : host_map_page + +PURPOSE : produces mapping from an Expanded Memory page to a + page in Intel physical address space + + +RETURNED STATUS : SUCCESS - mapping completed succesfully + FAILURE - error ocurred in mapping + +DESCRIPTION : Mapping achieved by mapping correct page from section into + Intel memory +========================================================================= +*/ +int host_map_page(SHORT EM_page_no, USHORT segment) +/* IN +short EM_page_no Expanded Memory page to be mapped in +unsigned short segment; segment in physical address space to map into +*/ + +{ + PVOID to; + int tstpage; + LARGE_INTEGER sec_offset; + ULONG viewSize; + NTSTATUS status; + + note_trace2(LIM_VERBOSE,"map page %d to segment 0x%4x", EM_page_no, segment); +#ifdef EMM_DEBUG + printf("host_map_page, segment=%x, EMpage=%x\n", + segment, EM_page_no); +#endif + + if (BaseOfLIMMem != NULL) + { + to = (PVOID)effective_addr(segment, 0); + + sec_offset.LowPart = EM_page_no * EMM_PAGE_SIZE; + sec_offset.HighPart = 0; + + viewSize = EMM_PAGE_SIZE; + + tstpage = (segment - get_base_address()) >> 10; + + /* detach from EMM page section */ + status = NtUnmapViewOfSection(processHandle, (PVOID)to); + if (!NT_SUCCESS(status)) + { + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + return(FALSE); + } + + if (processHandle == NULL) + { + DisplayErrorTerm(EHS_FUNC_FAILED,0,__FILE__,__LINE__); + return(FAILURE); + } + + /* attach to the section */ + status = NtMapViewOfSection(LIMSectionHandle, + processHandle, + &to, + 0, + EMM_PAGE_SIZE, + &sec_offset, + &viewSize, + ViewUnmap, + MEM_DOS_LIM, + PAGE_EXECUTE_READWRITE + ); + + if (!NT_SUCCESS(status)) + { + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + return(FAILURE); + } + return(SUCCESS); + } + return(FAILURE); +} + +/* +=========================================================================== + +FUNCTION : host_unmap_page + +PURPOSE :unmaps pages from Intel physical address space to an + Expanded Memory page + +RETURNED STATUS : SUCCESS - unmapping completed succesfully + FAILURE - error ocurred in mapping + +DESCRIPTION : Unmapping achieved by unampping view of section from + Intel memory + +========================================================================= +*/ +int host_unmap_page(USHORT segment, SHORT EM_page_no) +/* IN +unsigned short segment Segment in physical address space to unmap. +short EM_page_no Expanded Memory page currently mapped in +*/ +{ + PVOID from; + NTSTATUS status; + unsigned short phys_page_no; + + note_trace2(LIM_VERBOSE,"unmap page %d from segment 0x%.4x\n",EM_page_no,segment); + + + from = (PVOID)effective_addr(segment, 0); + +#ifdef EMM_DEBUG + printf("host_unmap_page, segment=%x, EMpage=%x\n", + segment, EM_page_no); +#endif + + /* detach from the LIM section */ + status = NtUnmapViewOfSection(processHandle, from); + if (!NT_SUCCESS(status)) + { + DisplayErrorTerm(EHS_FUNC_FAILED,status,__FILE__,__LINE__); + return(FAILURE); + } + + /* hold the block to avoid AV when applications touch unmapped pages */ + if (segment < 640 * 1024 / 16) { + if (!HoldEMMBackFillMemory(segment * 16, EMM_PAGE_SIZE)) + return FAILURE; + } + else { + + if (!hold_lim_page(segment)) { + note_trace1(LIM_VERBOSE, "couldn't hold lim page %d",get_segment_page_no(segment)); + return FAILURE; + } + } + return(SUCCESS); +} + +/* +=========================================================================== + +FUNCTION : host_alloc_page + +PURPOSE : searches the pagemap looking for a free page, allocates + that page and returns the EM page no. + +RETURNED STATUS : + SUCCESS - Always see note below + +DESCRIPTION : Steps through the Expanded memory Pagemap looking for + a clear bit, which indicates a free page. When found, + sets that bit and returns the page number. + For access purposes the pagemap is divided into long + word(32bit) sections + +NOTE : The middle layer calling routine (alloc_page()) checks + that all pages have not been allocated and therefore in + this implementation the returned status will always be + SUCCESS. + However alloc_page still checks for a return status of + SUCCESS, as some implementations may wish to allocate pages + dynamically and that may fail. +========================================================================= +*/ +SHORT host_alloc_page() +{ + SHORT EM_page_no; /* page number returned */ + LONG *ptr; /* ptr to 32 bit sections in */ + /* pagemap */ + SHORT i; /* index into 32 bit section */ + + ptr = (LONG *)EM_pagemap_address; + i =0; + EM_page_no = 0; + + while(*ptr & (MSB >> i++)) + { + EM_page_no++; + + if(i == 32) + /* + * start on next section + */ + { + ptr++; + i = 0; + } + } + /* + * Set bit to show that page is allocated + */ + *ptr = *ptr | (MSB >> --i); + + return(EM_page_no); +} + + +/* +=========================================================================== + +FUNCTION : host_free_page + +PURPOSE : marks the page indicated as being free for further + allocation + +RETURNED STATUS : + SUCCESS - Always - see note below + +DESCRIPTION : clears the relevent bit in the pagemap. + + For access purposes the pagemap is divided into long + word(32bit) sections. + +NOTE : The middle layer calling routine (free_page()) always + checks for invalid page numbers so in this implementation + the routine will always return SUCCESS. + However free_page() still checks for a return of SUCCESS + as other implementations may wish to use it. +========================================================================= +*/ +int host_free_page(SHORT EM_page_no) +/* IN SHORT EM_page_no page number to be cleared */ +{ + LONG *ptr; /* ptr to 32 bit sections in */ + /* pagemap */ + SHORT i; /* index into 32 bit section */ + + /* + * Set pointer to correct 32 bit section and index to correct bit + */ + + ptr = (long *)EM_pagemap_address; + ptr += (EM_page_no / 32); + i = EM_page_no % 32; + + /* + * clear bit + */ + *ptr = *ptr & ~(MSB >> i); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_copy routines + host_copy_con_to_con() + host_copy_con_to_EM() + host_copy_EM_to_con() + host_copy_EM_to_EM() + +PURPOSE : copies between conventional and expanded memory + + +RETURNED STATUS : + SUCCESS - Always - see note below + +DESCRIPTION : + The middle layer calling routine always checks for a + return of SUCCESS as other implementations may + return FAILURE. +========================================================================= +*/ +int host_copy_con_to_con(int length, USHORT src_seg, USHORT src_off, USHORT dst_seg, USHORT dst_off) + +/* IN +int length number of bytes to copy + +USHORT src_seg source segment address + src_off source offset address + dst_seg destination segment address + dst_off destination offset address +*/ +{ + sys_addr from, to; /* pointers used for copying */ + + from = effective_addr(src_seg, src_off); + to = effective_addr(dst_seg, dst_off); + + EM_moves(from, to, length); + + return(SUCCESS); +} + +int host_copy_con_to_EM(int length, USHORT src_seg, USHORT src_off, USHORT dst_page, USHORT dst_off) + +/* IN +int length number of bytes to copy + +USHORT src_seg source segment address + src_off source offset address + dst_page destination page number + dst_off destination offset within page +*/ +{ + UTINY *to; + sys_addr from; + + from = effective_addr(src_seg, src_off); + to = (char *)BaseOfLIMMem + dst_page * EMM_PAGE_SIZE + dst_off; + + EM_loads(from, to, length); + + return(SUCCESS); +} + +int host_copy_EM_to_con(int length, USHORT src_page, USHORT src_off, USHORT dst_seg, USHORT dst_off) +/* IN +int length number of bytes to copy + +USHORT src_page source page number + src_off source offset within page + dst_seg destination segment address + dst_off destination offset address +*/ +{ + UTINY *from; + sys_addr to; + + from = (char *)BaseOfLIMMem + (src_page * EMM_PAGE_SIZE + src_off); + to = effective_addr(dst_seg, dst_off); + + EM_stores(to, from, length); + + return(SUCCESS); +} + +int host_copy_EM_to_EM(int length, USHORT src_page, USHORT src_off, USHORT dst_page, USHORT dst_off) +/* IN +int length number of bytes to copy + +USHORT src_page source page number + src_off source offset within page + dst_page destination page number + dst_off destination offset within page +*/ +{ + unsigned char *from, *to; /* pointers used for copying */ + + from = (char *)BaseOfLIMMem + src_page * EMM_PAGE_SIZE + src_off; + to = (char *)BaseOfLIMMem + dst_page * EMM_PAGE_SIZE + dst_off; + + EM_memcpy(to, from, length); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_exchange routines + host_exchg_con_to_con() + host_exchg_con_to_EM() + host_exchg_EM_to_EM() + +PURPOSE : exchanges data between conventional and expanded memory + + +RETURNED STATUS : + SUCCESS - Everything ok + FAILURE - Memory allocation failure + +DESCRIPTION : + +========================================================================= +*/ +int host_exchg_con_to_con(int length, USHORT src_seg, USHORT src_off, USHORT dst_seg, USHORT dst_off) +/* IN +int length number of bytes to copy + +USHORT src_seg source segment address + src_off source offset address + dst_seg destination segment address + dst_off destination offset address +*/ +{ + UTINY *temp, *pointer;/* pointers used for copying */ + sys_addr to, from; + + if (length <= 64*1024) + temp = sas_scratch_address(length); + else + if ((temp = (unsigned char *)host_malloc(length)) == NULL) + return(FAILURE); + + pointer = temp; + + from = effective_addr(src_seg, src_off); + to = effective_addr(dst_seg, dst_off); + + EM_loads(from, pointer, length); /* source -> temp */ + EM_moves(to, from, length); /* dst -> source */ + EM_stores(to, pointer, length); /* temp -> dst */ + + if (length > 64*1024) + host_free(temp); + + return(SUCCESS); +} + +int host_exchg_con_to_EM(int length, USHORT src_seg, USHORT src_off, USHORT dst_page, USHORT dst_off) +/* IN +int length number of bytes to copy + +USHORT src_seg source segment address + src_off source offset address + dst_page destination page number + dst_off destination offset within page +*/ +{ + UTINY *to, *temp, *pointer;/* pointers used for copying */ + sys_addr from; + + //STF - performance improvement: if 4k aligned & >= 4k then can use + // (un)mapview to do exchange. + + if (length <= 64*1024) + temp = sas_scratch_address(length); + else + if ((temp = (unsigned char *)host_malloc(length)) == NULL) + return(FAILURE); + + pointer = temp; + + from = effective_addr(src_seg, src_off); + to = (char *)BaseOfLIMMem + dst_page * EMM_PAGE_SIZE + dst_off; + + EM_loads(from, pointer, length); + EM_stores(from, to, length); + EM_memcpy(to, pointer, length); + + if (length > 64*1024) + host_free(temp); + + return(SUCCESS); +} + +int host_exchg_EM_to_EM(int length, USHORT src_page, USHORT src_off, USHORT dst_page, USHORT dst_off) +/* IN +int length number of bytes to copy + +USHORT src_page source page number + src_off source offset within page + dst_page destination page number + dst_off destination offset within page +*/ +{ + UTINY *from, *to, *temp, *pointer; /* pointers used for copying */ + + if (length <= 64*1024) + temp = sas_scratch_address(length); + else + if ((temp = (unsigned char *)host_malloc(length)) == NULL) + return(FAILURE); + + pointer = temp; + + from = (char *)BaseOfLIMMem + src_page * EMM_PAGE_SIZE + src_off; + to = (char *)BaseOfLIMMem + dst_page * EMM_PAGE_SIZE + dst_off; + + EM_memcpy(pointer, from, length); + EM_memcpy(from, to, length); + EM_memcpy(to, pointer, length); + + if (length > 64*1024) + host_free(temp); + + return(SUCCESS); +} + + +/* +=========================================================================== + +FUNCTION : host_get_access_key + +PURPOSE : produces a random access key for use with LIM function 30 + 'Enable/Disable OS/E Function Set Functions' + +RETURNED STATUS : none + +DESCRIPTION : Two 16 bit random values are required for the 'access key' + We use the microsecond field from the get time of day routine + to provide this. + +========================================================================= +*/ +void host_get_access_key(USHORT access_key[2]) +/* OUT USHORT access_key[2] source segment address */ +{ + // do you think we need to seed the random # gen? + access_key[0] = rand() & 0xffff; + access_key[1] = rand() & 0xffff; + + return; +} +#endif /* MONITOR */ +#endif /* LIM */ |