diff options
Diffstat (limited to '')
-rw-r--r-- | private/mvdm/softpc.new/host/src/nt_det.c | 1611 |
1 files changed, 1611 insertions, 0 deletions
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 |