changeset 0:20b4ed4eebe3

Checked in Windows 9x display minidriver for VirtualBox.
author Michal Necasek <mnecasek@yahoo.com>
date Sun, 19 Jun 2022 17:39:17 +0200
parents
children 0c8e36318ee3
files .hgignore boxv.c boxv.h boxv9x.def boxv9x.inf boxv9x.lnk boxv_io.h boxvint.h dbgprint.c ddk/dibeng.def ddk/dibeng.h ddk/dibeng.lbc ddk/gdidefs.h ddk/minivdd.h ddk/valmode.h dibcall.c dibthunk.asm enable.c init.c makefile minidrv.h modes.c palette.c readdev.txt readme.txt res/colortab.c res/config.c res/display.rc res/display.rcv res/fonts.c res/fonts120.c res/fonttmpl.c scrsw.c sswhook.asm winhack.h
diffstat 35 files changed, 4488 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,13 @@
+# Use glob syntax.
+syntax: glob
+
+*.drv
+*.sym
+*.res
+*.bin
+*.obj
+*.lib
+*.map
+*.err
+dist
+boxv9x.img
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,169 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Core boxv implementation. */
+
+#include "boxv.h"       /* Public interface. */
+#include "boxvint.h"    /* Implementation internals. */
+#include "boxv_io.h"    /* I/O access layer, host specific. */
+
+
+/* Write a single value to an indexed register at a specified
+ * index. Suitable for the CRTC or graphics controller.
+ */
+inline void vid_wridx( void *cx, int idx_reg, int idx, v_byte data )
+{
+    vid_outw( cx, idx_reg, idx | (data << 8) );
+}
+
+/* Set an extended non-VGA mode with given parameters. 8bpp and higher only.
+ * Returns non-zero value on failure.
+ */
+int BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres )
+{
+    /* Do basic parameter validation. */
+    if( v_xres < xres || v_yres < yres )
+        return( -1 );
+
+    /* Put the hardware into a state where the mode can be safely set. */
+    vid_inb( cx, VGA_STAT_ADDR );                   /* Reset flip-flop. */
+    vid_outb( cx, VGA_ATTR_W, 0 );                  /* Disable palette. */
+    vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR_RESET );
+
+    /* Disable the extended display registers. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED );
+
+    /* Program the extended non-VGA registers. */
+
+    /* Set X resoultion. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, xres );
+    /* Set Y resoultion. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, yres );
+    /* Set bits per pixel. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, bpp );
+    /* Set the virtual resolution. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_xres );
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_yres );
+    /* Reset the current bank. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BANK );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+    /* Set the X and Y display offset to 0. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 );
+    /* Enable the extended display registers. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC );
+
+    /* Re-enable the sequencer. */
+    vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR0_NORESET );
+
+    /* Reset flip-flop again and re-enable palette. */
+    vid_inb( cx, VGA_STAT_ADDR );
+    vid_outb( cx, VGA_ATTR_W, 0x20 );
+
+    return( 0 );
+}
+
+/* Program the DAC. Each of the 'count' entries is 4 bytes in size,
+ * red/green/blue/unused.
+ * Returns non-zero on failure.
+ */
+int BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal )
+{
+    v_byte      *prgbu = pal;
+
+    /* Basic argument validation. */
+    if( start + count > 256 )
+        return( -1 );
+
+    /* Write the starting index. */
+    vid_outb( cx, VGA_DAC_W_INDEX, start );
+    /* Load the RGB data. */
+    while( count-- ) {
+        vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+        vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+        vid_outb( cx, VGA_DAC_DATA, *prgbu++ );
+        ++prgbu;
+    }
+    return( 0 );
+}
+
+/* Detect the presence of a supported adapter and amount of installed
+ * video memory. Returns zero if not found.
+ */
+int BOXV_detect( void *cx, unsigned long *vram_size )
+{
+    v_word      boxv_id;
+
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID );
+    boxv_id = vid_inw( cx, VBE_DISPI_IOPORT_DATA );
+    if( vram_size ) {
+        *vram_size = vid_ind( cx, VBE_DISPI_IOPORT_DATA );
+    }
+    if( boxv_id >= VBE_DISPI_ID0 && boxv_id <= VBE_DISPI_ID4 )
+        return( boxv_id );
+    else
+        return( 0 );
+}
+
+/* Disable extended mode and place the hardware into a VGA compatible state.
+ * Returns non-zero on failure.
+ */
+int BOXV_ext_disable( void *cx )
+{
+    /* Disable the extended display registers. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE );
+    vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED );
+    return( 0 );
+}
+
+/* Return the physical base address of the framebuffer. Needed in environments
+ * that do not query the base through PCI.
+ */
+unsigned long BOXV_get_lfb_base( void *cx )
+{
+    unsigned long   fb_base;
+
+    /* Ask the virtual hardware for the high 16 bits. */
+    vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_FB_BASE_HI );
+    fb_base = vid_inw( cx, VBE_DISPI_IOPORT_DATA );
+
+    /* Old versions didn't support that, so use the default
+     * if the value looks like garbage.
+     */
+    if( fb_base != 0 && fb_base != 0xffff )
+        fb_base = fb_base << 16;
+    else
+        fb_base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+
+    return( fb_base );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,49 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/*
+ * Public interface to the boxv library.
+ */
+
+/* PCI vendor and device IDs. */
+#define BOXV_PCI_VEN    0x80EE
+#define BOXV_PCI_DEV    0xBEEF
+
+/* A structure describing mode information. Note: The mode numbers
+ * usually match VBE, but this should not be relied upon.
+ */
+typedef struct {
+    int     mode_no;        /* Mode number */
+    int     xres;           /* Horizontal resolution */
+    int     yres;           /* Vertical resolution */
+    int     bpp;            /* Color depth */
+} BOXV_mode_t;
+
+extern void BOXV_mode_enumerate( void *cx, int (cb)( void *cx, BOXV_mode_t *mode ) );
+extern int  BOXV_detect( void *cx, unsigned long *vram_size );
+extern int  BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres );
+extern int  BOXV_mode_set( void *cx, int mode_no );
+extern int  BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal );
+extern int  BOXV_ext_disable( void *cx );
+extern unsigned long BOXV_get_lfb_base( void *cx );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv9x.def	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,67 @@
+;
+; Standard display driver .DEF file
+;
+LIBRARY DISPLAY
+
+;
+; The magic numbers are: Aspect ratio, Horizontal DPI, Vertical DPI
+;
+DESCRIPTION 'DISPLAY : 100, 96, 96 : DIB Engine based Mini display driver.'
+EXETYPE WINDOWS
+
+DATA PRELOAD FIXED SINGLE
+
+SEGMENTS
+    _TEXT       PRELOAD  SHARED
+    _INIT       PRELOAD  MOVEABLE 
+
+EXPORTS
+    BitBlt                 @1
+    ColorInfo              @2
+    Control                @3
+    Disable                @4
+    Enable                 @5
+    EnumDFonts             @6
+    EnumObj                @7
+    Output                 @8
+    Pixel                  @9
+    RealizeObject          @10
+    StrBlt                 @11
+    ScanLR                 @12
+    DeviceMode             @13     NODATA
+
+    ExtTextOut             @14
+    GetCharWidth           @15     NODATA
+    DeviceBitmap           @16     NODATA
+    FastBorder             @17
+    SetAttribute           @18     NODATA
+
+    DibBlt                 @19             ; Device Independent Bitmap group
+    CreateDIBitmap         @20
+    DibToDevice            @21
+
+    SetPalette             @22             ; Windows 3.0 palette group
+    GetPalette             @23
+
+    SetPaletteTranslate    @24
+    GetPaletteTranslate    @25
+    UpdateColors           @26
+    StretchBlt             @27
+    StretchDIBits          @28
+
+    SelectBitmap           @29
+    BitmapBits             @30
+    ReEnable               @31
+
+    Inquire                @101            ; Mouse cursor function group
+    SetCursor              @102
+    MoveCursor             @103
+    CheckCursor            @104
+
+    GetDriverResourceID    @450            ; Undocumented USER callback
+    UserRepaintDisable     @500            ; Undocumented USER callback
+
+    ValidateMode	        @700
+
+IMPORTS
+    GlobalSmartPageLock = KERNEL.230       ; Undocumented function
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv9x.inf	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,118 @@
+;
+; INF file for VirtualBox Win9x display driver
+; Copyright 2012-2022, The OS/2 Museum
+
+[version]
+Class=DISPLAY
+signature="$CHICAGO$"
+Provider=%Mfg%
+
+[DestinationDirs]
+DefaultDestDir  = 11	; LDID_SYS
+BoxV.Copy = 11
+
+[SourceDisksNames]
+; BOXV9X is the driver disk volume label
+1="VirtualBox Win9x Display Driver Disk",BOXV9X,1
+
+[SourceDisksFiles]
+boxvmini.drv=1
+;boxvmini.vxd=1
+
+[Manufacturer]
+%Mfg%=Mfg.BoxV
+
+[Mfg.BoxV]
+%PCI\VEN_80EE&DEV_BEEF.DeviceDesc%=BoxV,PCI\VEN_80EE&DEV_BEEF
+
+[BoxV]
+CopyFiles=BoxV.Copy
+DelReg=Prev.DelReg
+AddReg=BoxV_AddReg
+
+[BoxV.Copy]
+boxvmini.drv
+;boxvmini.vxd
+
+[Prev.DelReg]
+HKR,,Ver
+HKR,,DevLoader
+HKR,DEFAULT
+HKR,MODES
+HKR,CURRENT
+
+[BoxV_AddReg]
+HKR,,Ver,,4.0
+HKR,,DevLoader,,*vdd
+HKR,DEFAULT,Mode,,"8,640,480"
+HKR,DEFAULT,drv,,boxvmini.drv
+HKR,DEFAULT,vdd,,"*vdd,*vflatd"
+;HKR,DEFAULT,minivdd,,boxvmini.vxd
+;HKR,DEFAULT,carddvdd,,cardsamp.vxd
+HKR,DEFAULT,RefreshRate,,-1
+HKR,DEFAULT,DDC,,1
+HKR,DEFAULT,ExtModeSwitch,,0
+HKR,"MODES\4\640,480",drv,,vga.drv
+HKR,"MODES\4\640,480",vdd,,*vdd
+HKR,"MODES\4\800,600",drv,,supervga.drv
+HKR,"MODES\4\800,600",vdd,,*vdd
+HKR,"MODES\8\640,480"
+HKR,"MODES\8\800,600"
+HKR,"MODES\8\1024,768"
+HKR,"MODES\8\1152,864"
+HKR,"MODES\8\1280,720"
+HKR,"MODES\8\1280,800"
+HKR,"MODES\8\1280,960"
+HKR,"MODES\8\1280,1024"
+HKR,"MODES\8\1400,1050"
+HKR,"MODES\8\1600,1200"
+HKR,"MODES\8\1600,900"
+HKR,"MODES\8\1680,1050"
+HKR,"MODES\8\1920,1080"
+HKR,"MODES\8\1920,1200"
+HKR,"MODES\16\640,480"
+HKR,"MODES\16\800,600"
+HKR,"MODES\16\1024,768"
+HKR,"MODES\16\1152,864"
+HKR,"MODES\16\1280,720"
+HKR,"MODES\16\1280,800"
+HKR,"MODES\16\1280,960"
+HKR,"MODES\16\1280,1024"
+HKR,"MODES\16\1400,1050"
+HKR,"MODES\16\1600,900"
+HKR,"MODES\16\1600,1200"
+HKR,"MODES\16\1680,1050"
+HKR,"MODES\16\1920,1080"
+HKR,"MODES\16\1920,1200"
+HKR,"MODES\24\640,480"
+HKR,"MODES\24\800,600"
+HKR,"MODES\24\1024,768"
+HKR,"MODES\24\1152,864"
+HKR,"MODES\24\1280,720"
+HKR,"MODES\24\1280,800"
+HKR,"MODES\24\1280,960"
+HKR,"MODES\24\1280,1024"
+HKR,"MODES\24\1400,1050"
+HKR,"MODES\24\1600,900"
+HKR,"MODES\24\1600,1200"
+HKR,"MODES\24\1680,1050"
+HKR,"MODES\24\1920,1080"
+HKR,"MODES\24\1920,1200"
+HKR,"MODES\32\640,480"
+HKR,"MODES\32\800,600"
+HKR,"MODES\32\1024,768"
+HKR,"MODES\32\1152,864"
+HKR,"MODES\32\1280,720"
+HKR,"MODES\32\1280,800"
+HKR,"MODES\32\1280,960"
+HKR,"MODES\32\1280,1024"
+HKR,"MODES\32\1400,1050"
+HKR,"MODES\32\1600,900"
+HKR,"MODES\32\1600,1200"
+HKR,"MODES\32\1680,1050"
+HKR,"MODES\32\1920,1080"
+HKR,"MODES\32\1920,1200"
+
+[Strings]
+Mfg="VirtualBox"
+PCI\VEN_80EE&DEV_BEEF.DeviceDesc="VirtualBox SVGA PCI"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv9x.lnk	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,61 @@
+# This file produced by MS2WLINK
+system windows dll initglobal
+file dibthunk.obj
+file dibcall.obj
+file enable.obj
+file init.obj
+file palette.obj
+file scrsw.obj
+file sswhook.obj
+file modes.obj
+file boxv.obj
+name boxvmini.drv
+option map=boxvmini.map
+library dibeng.lib
+library clibs.lib
+option modname=DISPLAY
+option description 'DISPLAY : 100, 96, 96 : DIB Engine based Mini display driver.'
+option oneautodata
+segment type data preload fixed
+# definition file segments keyword handled differently in WLINK
+segment '_TEXT'  preload shared
+segment '_INIT'  preload moveable
+export BitBlt.1
+export ColorInfo.2
+export Control.3
+export Disable.4
+export Enable.5
+export EnumDFonts.6
+export EnumObj.7
+export Output.8
+export Pixel.9
+export RealizeObject.10
+export StrBlt.11
+export ScanLR.12
+export DeviceMode.13
+export ExtTextOut.14
+export GetCharWidth.15
+export DeviceBitmap.16
+export FastBorder.17
+export SetAttribute.18
+export DibBlt.19
+export CreateDIBitmap.20
+export DibToDevice.21
+export SetPalette.22
+export GetPalette.23
+export SetPaletteTranslate.24
+export GetPaletteTranslate.25
+export UpdateColors.26
+export StretchBlt.27
+export StretchDIBits.28
+export SelectBitmap.29
+export BitmapBits.30
+export ReEnable.31
+export Inquire.101
+export SetCursor.102
+export MoveCursor.103
+export CheckCursor.104
+export GetDriverResourceID.450
+export UserRepaintDisable.500
+export ValidateMode.700
+import GlobalSmartPageLock  KERNEL.230
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxv_io.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,67 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+#include <conio.h>  /* For port I/O prototypes. */
+
+/* The 16-bit compiler does not do inpd(). We have to do it ourselves.
+ * NB: It might be OK to trash the high bits of EAX but better be safe.
+ */
+/* Warning: Destroys high bits of EAX. */
+unsigned long inpd( unsigned port );
+#pragma aux inpd =      \
+    ".386"              \
+    "push   eax"        \
+    "in     eax, dx"    \
+    "mov    dx, ax"     \
+    "shr    eax, 16"    \
+    "xchg   bx, ax"     \
+    "pop    eax"        \
+    "xchg   bx, ax"     \
+    "xchg   ax, dx"     \
+    parm [dx] value [dx ax] modify [bx] nomemory;
+
+static void vid_outb( void *cx, unsigned port, unsigned val )
+{
+    outp( port, val );
+}
+
+static void vid_outw( void *cx, unsigned port, unsigned val )
+{
+    outpw( port, val );
+}
+
+static unsigned vid_inb( void *cx, unsigned port )
+{
+    return( inp( port ) );
+}
+
+static unsigned vid_inw( void *cx, unsigned port )
+{
+    return( inpw( port ) );
+}
+
+static unsigned long vid_ind( void *cx, unsigned port )
+{
+    return( inpd( port ) );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/boxvint.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,149 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Internal definitions used by the boxv library. */
+
+/*-------------- VGA Specific ----------------*/
+
+/* VGA I/O port addresses. */
+#define VGA_CRTC            0x3D4   /* Color only! */
+#define VGA_ATTR_W          0x3C0
+#define VGA_ATTR_R          0x3C1
+#define VGA_MISC_OUT_W      0x3C2
+#define VGA_SEQUENCER       0x3C4
+#define VGA_SEQUENCER_DATA  0x3C5
+#define VGA_PIXEL_MASK      0x3C6
+#define VGA_DAC_W_INDEX     0x3C8
+#define VGA_DAC_DATA        0x3C9
+#define VGA_MISC_OUT_R      0x3CC
+#define VGA_GRAPH_CNTL      0x3CE
+#define VGA_GRAPH_CNTL_DATA 0x3CF
+#define VGA_STAT_ADDR       0x3DA   /* Color only! */
+
+/* VGA Attribute Controller register indexes. */
+#define VGA_AR_MODE         0x10
+#define VGA_AR_OVERSCAN     0x11
+#define VGA_AR_PLANE_EN     0x12
+#define VGA_AR_PIX_PAN      0x13
+#define VGA_AR_COLOR_SEL    0x14
+
+/* VGA Graphics Controller register indexes. */
+#define VGA_GR_SET_RESET    0x00
+#define VGA_GR_DATA_ROTATE  0x03
+#define VGA_GR_READ_MAP_SEL 0x04
+#define VGA_GR_MODE         0x05
+#define VGA_GR_MISC         0x06
+#define VGA_GR_BIT_MASK     0x08
+
+/* VGA Sequencer register indexes. */
+#define VGA_SR_RESET        0x00
+#define VGA_SR_CLK_MODE     0x01
+#define VGA_SR_PLANE_MASK   0x02
+#define VGA_SR_MEM_MODE     0x04
+
+/* Sequencer constants. */
+#define VGA_SR0_NORESET     0x03
+#define VGA_SR0_RESET       0x00
+#define VGA_SR1_BLANK       0x20
+
+/* VGA CRTC register indexes. */
+#define VGA_CR_HORZ_TOTAL   0x00
+#define VGA_CR_CUR_START    0x0A
+#define VGA_CR_CUR_END      0x0B
+#define VGA_CR_START_HI     0x0C
+#define VGA_CR_START_LO     0x0D
+#define VGA_CR_CUR_POS_HI   0x0E
+#define VGA_CR_CUR_POS_LO   0x0F
+#define VGA_CR_VSYNC_START  0x10
+#define VGA_CR_VSYNC_END    0x11
+
+/* VGA Input Status Register 1 constants. */
+#define VGA_STAT_VSYNC      0x08
+
+/*------------ End VGA Specific --------------*/
+
+/*------------- bochs Specific ---------------*/
+
+#define VBE_DISPI_BANK_ADDRESS          0xA0000
+#define VBE_DISPI_BANK_SIZE_KB          64
+
+#define VBE_DISPI_MAX_XRES              1024
+#define VBE_DISPI_MAX_YRES              768
+
+#define VBE_DISPI_IOPORT_INDEX          0x01CE
+#define VBE_DISPI_IOPORT_DATA           0x01CF
+
+#define VBE_DISPI_INDEX_ID              0x0
+#define VBE_DISPI_INDEX_XRES            0x1
+#define VBE_DISPI_INDEX_YRES            0x2
+#define VBE_DISPI_INDEX_BPP             0x3
+#define VBE_DISPI_INDEX_ENABLE          0x4
+#define VBE_DISPI_INDEX_BANK            0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+#define VBE_DISPI_INDEX_X_OFFSET        0x8
+#define VBE_DISPI_INDEX_Y_OFFSET        0x9
+#define VBE_DISPI_INDEX_VBOX_VIDEO      0xa
+#define VBE_DISPI_INDEX_FB_BASE_HI      0xb
+
+#define VBE_DISPI_ID0                   0xB0C0
+#define VBE_DISPI_ID1                   0xB0C1
+#define VBE_DISPI_ID2                   0xB0C2
+#define VBE_DISPI_ID3                   0xB0C3
+#define VBE_DISPI_ID4                   0xB0C4
+
+#define VBE_DISPI_DISABLED              0x00
+#define VBE_DISPI_ENABLED               0x01
+#define VBE_DISPI_GETCAPS               0x02
+#define VBE_DISPI_8BIT_DAC              0x20
+#define VBE_DISPI_LFB_ENABLED           0x40
+#define VBE_DISPI_NOCLEARMEM            0x80
+
+/* Default LFB base. Might be different! */
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+/*------------ End bochs Specific -------------*/
+
+
+typedef unsigned char   v_byte;
+typedef unsigned short  v_word;
+
+/* A structure describing the contents of VGA registers for a mode set. */
+typedef struct {
+    v_byte          misc;           /* Miscellaneous register. */
+    v_byte          seq[5];         /* Sequencer registers. */
+    v_byte          crtc[25];       /* CRTC registers. */
+    v_byte          gctl[9];        /* Graphics controller registers. */
+    v_byte          atr[21];        /* Attribute registers. */
+} v_vgaregs;
+
+/* A structure fully describing a graphics or text mode. */
+typedef struct {
+    int             mode_no;        /* Internal mode number. */
+    int             xres;           /* Horizontal (X) resolution. */
+    int             yres;           /* Vertical (Y) resolution. */
+    int             bpp;            /* Bits per pixel. */
+    int             ext;            /* Non-zero for extended modes. */
+    v_vgaregs      *vgaregs;       /* Contents of VGA registers. */
+} v_mode;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgprint.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,228 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Homegrown printf support. The C runtime printf() is hard to use without
+ * dragging in much of the library, and much worse, the small model runtime                                                                              .
+ * can't operate with SS != DS. So we roll our own very simplified printf()                                                                                    .
+ * subset, good enough for what we need.                                                                            .
+ */
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <conio.h>
+
+
+/* Backdoor logging I/O ports. */
+#define INFO_PORT   0x504
+#define DEBUG_PORT  0x403
+
+#pragma code_seg( _INIT );
+
+static void prt_ch( char c )
+{
+    outp( INFO_PORT, c );
+}
+
+static void prt_u32( uint32_t val, int width )
+{
+    uint32_t    uval;
+    uint32_t    base;
+    char        buf[16];    /* It's 12 digits max. */
+    int         n = 0;
+
+    uval = val;
+
+    do {
+        base = uval / 10;
+        buf[n++] = uval - base * 10 + '0';
+        uval = base;
+    } while( uval );
+
+    /* Pad with spaces. */
+    while( width > n ) {
+        prt_ch( ' ' );
+        --width;
+    }
+
+    do {
+        prt_ch( buf[--n] );
+    } while( n );
+}
+
+static void prt_i32( int32_t val, int width )
+{
+    uint32_t    uval;
+
+    if( val < 0 ) {
+        prt_ch( '-' );
+        uval = -val;
+        if( width > 0 )
+            --width;
+    } else {
+        uval = val;
+    }
+
+    prt_u32( uval, width );
+}
+
+static void prt_hex32( uint32_t val, int width, char hexa )
+{
+    char    buf[8]; /* Enough for a dword. */
+    int     n = 0;
+    int     nibble;
+
+    do {
+        nibble = val & 0xF;
+        val >>= 4;
+        buf[n++] = nibble + (nibble > 9 ? hexa - 10 : '0');
+    } while( val );
+
+    /* Pad with zeros. */
+    while( width > n ) {
+        prt_ch( '0' );
+        --width;
+    }
+
+    do {
+        prt_ch( buf[--n] );
+    } while( n );
+}
+
+static void prt_str( const char __far *s )
+{
+    while( *s )
+        prt_ch( *s++ );
+}
+
+void dbg_printf( const char *s, ... )
+{
+    char        type_len;
+    char        conv;
+    char        hexa;
+    int         width;
+    uint16_t    word;
+    uint32_t    dword;
+    va_list     args;
+
+    va_start( args, s );
+
+    /* Go until end of format string. */
+    while( *s ) {
+        /* Is it a format specifier? */
+        if( *s == '%' ) {
+            ++s;    /* Eat the % sign. */
+            conv     = 0;
+            width    = 0;
+            type_len = 0;
+
+            /* Process field width, if any. */
+            while( isdigit( *s ) ) {
+                width *= 10;
+                width += *s++ - '0';
+            }
+
+            /* Process type length specifier, if any. */
+            switch( *s ) {
+            case 'l':   /* Long integers. */
+            case 'W':   /* Far pointers. */
+                type_len = *s++;
+                break;
+            default:    /* Do nothing. */
+                break;
+            }
+
+            /* Now check if a supported conversion is there. */
+            switch( *s ) {
+            case 'c':
+            case 'd':
+            case 'u':
+            case 'p':
+            case 'P':
+            case 's':
+            case 'x':
+            case 'X':
+                conv = *s++;
+                break;
+            default:    /* Do nothing. */
+                break;
+            }
+
+            if( conv ) {
+                /* Time to start grabbing stuff off the stack. */
+                word = va_arg( args, uint16_t );
+                /* If argument is double wide, build a doubleword. */
+                if( type_len == 'l' || type_len == 'W' ) {
+                    dword = va_arg( args, uint16_t );
+                    dword <<= 16;
+                    dword |= word;
+                }
+                if( conv == 'c' ) {
+                    prt_ch( word );
+                } else if( conv == 'd' ) {
+                    if( type_len == 'l' )
+                        prt_i32( dword, width );
+                    else
+                        prt_i32( (int16_t)word, width );
+                } else if( conv == 'u' ) {
+                    if( type_len == 'l' )
+                        prt_u32( dword, width );
+                    else
+                        prt_u32( word, width );
+                } else if( conv == 'p' || conv == 'P' ) {
+                    hexa = conv - 'P' + 'A';
+                    if( type_len == 'W' ) {
+                        prt_hex32( dword >> 16, 4, hexa );
+                        prt_ch( ':' );
+                        prt_hex32( word, 4, hexa );
+                    } else {
+                        prt_hex32( word, 4, hexa );
+                    }
+                } else if( conv == 's' ) {
+                    if( type_len == 'W' )
+                        prt_str( (const char __far *)dword );
+                    else
+                        prt_str( (const char *)word );
+                } else if( conv == 'x' || conv == 'X' ) {
+                    hexa = conv - 'X' + 'A';
+                    if( type_len == 'l' ) {
+                        if( !width )
+                            width = 8;
+                        prt_hex32( dword, width, hexa );
+                    } else {
+                        if( !width )
+                            width = 4;
+                        prt_hex32( word, width, hexa );
+                    }
+                }
+            } else {
+                /* Just print whatever is there. */
+                prt_ch( *s++ );
+            }
+        } else {
+            prt_ch( *s++ );
+        }
+    }
+    va_end( args );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/dibeng.def	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,49 @@
+EXPORTS
+LIBRARY    DIBENG
+    DIB_BitBlt                     @1
+    DIB_ColorInfo                  @2
+    DIB_Control                    @3
+    DIB_Disable                    @4
+    DIB_Enable                     @5
+    DIB_EnumDFonts                 @6
+    DIB_EnumObj                    @7
+    DIB_Output                     @8
+    DIB_Pixel                      @9
+    DIB_RealizeObject              @10
+    DIB_StrBlt                     @11
+    DIB_ScanLR                     @12
+    DIB_DeviceMode                 @13
+    DIB_ExtTextOut                 @14
+    DIB_GetCharWidth               @15
+    DIB_DeviceBitmap               @16
+    DIB_FastBorder                 @17
+    DIB_SetAttribute               @18
+    DIB_DibBlt                     @19
+    DIB_CreateDIBitmap             @20
+    DIB_DibToDevice                @21
+    DIB_SetPalette                 @22
+    DIB_GetPalette                 @23
+    DIB_SetPaletteTranslate        @24
+    DIB_GetPaletteTranslate        @25
+    DIB_UpdateColors               @26
+    DIB_StretchBlt                 @27
+    DIB_StretchDIBits              @28
+    DIB_SelectBitmap               @29
+    DIB_BitmapBits                 @30
+    DIB_Inquire                    @101
+    DIB_SetCursorExt               @102
+    DIB_MoveCursorExt              @103
+    DIB_CheckCursorExt             @104
+    DIB_BeginAccess                @105
+    DIB_EndAccess                  @106
+    CreateDIBPDevice               @300
+    DIB_RealizeObjectExt           @400
+    DIB_DibBltExt                  @401
+    DIB_EnumObjExt                 @402
+    DIB_ExtTextOutExt              @403
+    DIB_UpdateColorsExt            @404
+    DIB_SetPaletteExt              @405
+    DIB_GetPaletteExt              @406
+    DIB_SetPaletteTranslateExt     @407
+    DIB_GetPaletteTranslateExt     @408
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/dibeng.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,242 @@
+/* DIB Engine interface. */
+
+#define BRUSHSIZE       8
+#define VER_DIBENG      0x400
+#define TYPE_DIBENG     0x5250  /* 'RP' */
+
+#define deCursorExclude     deBeginAccess
+#define deCursorUnexclude   deEndAccess
+
+/* DIB Engine PDevice structure. The deType field will be 'DI' when GDI
+ * calls the Engine; deType will be null or a selector if a minidriver is
+ * calls the DIB Engine.
+ */
+typedef struct {
+    WORD         deType;                    /* TYPE_DIBENG or zero.  */
+    WORD         deWidth;                   /* DIB width in pixels. */
+    WORD         deHeight;                  /* DIB height in pixels. */
+    WORD         deWidthBytes;              /* Scanline length in bytes. */
+    BYTE         dePlanes;                  /* Number of bit planes. */
+    BYTE         deBitsPixel;               /* Number of bits per pixel. */
+    DWORD        deReserved1;               /* Not used. */
+    DWORD        deDeltaScan;               /* Scanline delta, can be negative.*/
+    LPBYTE       delpPDevice;               /* Associated PDevice pointer. */
+    DWORD        deBitsOffset;              /* 48-bit pointer to */
+    WORD         deBitsSelector;            /* DIB bits storage. */
+    WORD         deFlags;                   /* More flags. */
+    WORD         deVersion;                 /* Major/minor (0400h = 4.0). */
+    LPBITMAPINFO deBitmapInfo;              /* Bitmapinfo header pointer. */
+    void         (WINAPI *deBeginAccess)(); /* Surface access begin callback. */
+    void         (WINAPI *deEndAccess)();   /* Surface access end callback. */
+    DWORD        deDriverReserved;          /* Reserved for minidrivers. */
+} DIBENGINE, FAR *LPDIBENGINE;
+
+/* DIBEngine.deFlags */
+#define MINIDRIVER      0x0001  /* Mini display driver. */
+#define PALETTIZED      0x0002  /* Has a palette. */
+#define SELECTEDDIB     0x0004  /* DIB Section. */
+#define OFFSCREEN       0x0008  /* Offscreen surface in VRAM. */
+#define BUSY            0x0010  /* Busy. */
+#define NOT_FRAMEBUFFER 0x0020  /* No FB access (like 8514/A). */
+#define FIVE6FIVE       0x0040  /* 5-6-5 16bpp mode. */
+#define NON64KBANK      0x0080  /* Bank size != 64K. */
+#define VRAM            0x8000	/* Have VRAM access. */
+#define BANKEDVRAM      0x4000  /* VFlatD simulating LFB. */
+#define BANKEDSCAN      0x2000  /* VFlatD with scanlines crossing banks. */
+#define PALETTE_XLAT    0x1000  /* Bkgnd palette translation. */
+#define VGADITHER       0x0800  /* Dither to VGA colors. */
+#define CTCHANGE        0x0400  /* Color table changed/ */
+#define DITHER256       0x0200  /* Dither to 256 colors. */
+
+#define BUSY_BIT        4       /* Number of bit to test for busy. */
+
+/* DIB_Brush??.dp??BrushFlags */
+#define COLORSOLID      0x01    /* Color part solid. */
+#define MONOSOLID       0x02    /* Mono part solid. */
+#define PATTERNMONO     0x04    /* Brush originated from mono bitmap. */
+#define MONOVALID       0x08    /* Mono part valid. */
+#define MASKVALID       0x10    /* Mask valid. */
+#define PRIVATEDATA     0x20    /* Vendor defined bit. */
+
+/* Fake typedefs to avoid conflicts between windows.h and gdidefs.h. */
+typedef LPVOID LPPDEVICE;
+typedef LPVOID LPPPEN;
+typedef LPVOID LPPBRUSH;
+typedef LPVOID LPBRUSH;
+typedef LPVOID LPPCOLOR;
+typedef LPINT  LPSHORT;
+
+/* DIB Engine functions. */
+/* NB: Based on DDK documentation which may be inaccurate. */
+extern void     WINAPI  DIB_Control( void );
+extern WORD     WINAPI  DIB_EnumObjExt( LPPDEVICE lpDestDev, WORD wStyle, FARPROC lpCallbackFunc,
+                                        LPVOID lpClientData, LPPDEVICE lpDisplayDev );
+extern VOID     WINAPI  DIB_CheckCursorExt( LPPDEVICE lpDevice );
+extern WORD     WINAPI  DIB_Output( LPPDEVICE lpDestDev, WORD wStyle, WORD wCount,
+                                    LPPOINT lpPoints, LPPPEN lpPPen, LPPBRUSH lpPBrush,
+                                    LPDRAWMODE lpDrawMode, LPRECT lpClipRect);
+extern DWORD    WINAPI  DIB_RealizeObject( LPPDEVICE lpDestDev, WORD wStyle, LPVOID lpInObj,
+                                           LPVOID lpOutObj, LPTEXTXFORM lpTextXForm );
+extern WORD     WINAPI  DIB_RealizeObjectExt( LPPDEVICE lpDestDev, WORD wStyle, LPVOID lpInObj,
+                                              LPVOID lpOutObj, LPTEXTXFORM lpTextXForm,
+                                              LPPDEVICE lpDisplayDev );
+extern BOOL     WINAPI  DIB_BitBlt( LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY, LPPDEVICE lpSrcDev,
+                                    WORD wSrcX, WORD wSrcY, WORD wXext, WORD wYext, DWORD dwRop3,
+                                    LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode );
+extern BOOL     WINAPI  DIB_BitmapBits( LPPDEVICE lpDevice, DWORD fFlags, DWORD dwCount, LPSTR lpBits );
+extern VOID     WINAPI  DIB_DibBlt( LPPDEVICE lpBitmap, WORD fGet, WORD iStart, WORD cScans, LPSTR lpDIBits,
+                                    LPBITMAPINFO lpBitmapInfo, LPDRAWMODE lpDrawMode, LPINT lpTranslate );
+extern WORD     WINAPI  DIB_DibToDevice( LPPDEVICE lpDestDev, WORD X, WORD Y, WORD iScan, WORD cScans,
+                                         LPRECT lpClipRect, LPDRAWMODE lpDrawMode, LPSTR lpDIBits,
+                                         LPBITMAPINFO lpBitmapInfo, LPINT lpTranslate );
+extern DWORD    WINAPI  DIB_Pixel( LPPDEVICE lpDestDev, WORD X, WORD Y, DWORD dwPhysColor, LPDRAWMODE lpDrawMode );
+extern WORD     WINAPI  DIB_ScanLR( LPPDEVICE lpDestDev, WORD X, WORD Y, DWORD dwPhysColor, WORD wStyle );
+extern BOOL     WINAPI  DIB_SelectBitmap(LPPDEVICE lpDevice, LPBITMAP lpPrevBitmap, LPBITMAP lpBitmap, DWORD fFlags );
+extern BOOL     WINAPI  DIB_StretchBlt( LPPDEVICE lpDestDev, WORD wDestX, WORD wDestY, WORD wDestWidth,
+                                        WORD wDestHeight, LPPDEVICE lpSrcDev, WORD wSrcX, WORD wSrcY,
+                                        WORD wSrcWidth, WORD wtSrcHeight, DWORD dwRop3, LPBRUSH lpPBrush,
+                                        LPDRAWMODE lpDrawMode, LPRECT lpClipRect );
+extern BOOL     WINAPI  DIB_StretchDIBits( LPPDEVICE lpDestDev, WORD fGet, WORD wDestX, WORD wDestY, WORD wDestWidth,
+                                           WORD wDestHeight, WORD wSrcX, WORD wSrcY, WORD wSrcWidth, WORD wSrcHeight,
+                                           VOID *lpBits, LPBITMAPINFO lpInfo, LPINT lpTranslate, DWORD dwRop3,
+                                           LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode, LPRECT lpClipRect );
+extern DWORD    WINAPI  DIB_ExtTextOut( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect,
+                                        LPSTR lpString, int wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
+                                        LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths, LPRECT lpOpaqueRect, WORD wOptions );
+extern DWORD    WINAPI  DIB_ExtTextOutExt( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect,
+                                           LPSTR lpString, WORD wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode,
+                                           LPTEXTXFORM lpTextXForm, LPSHORT lpCharWidths, LPRECT lpOpaqueRect,
+                                           WORD wOptions, LPVOID *lpDrawTextBitmap, LPVOID *lpDrawRect );
+extern WORD     WINAPI  DIB_GetCharWidth( LPPDEVICE lpDestDev, LPWORD lpBuffer, WORD wFirstChar, WORD wLastChar,
+                                          LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode, LPTEXTXFORM lpFontTrans );
+
+extern DWORD    WINAPI  DIB_StrBlt( LPPDEVICE lpDestDev, WORD wDestXOrg, WORD wDestYOrg, LPRECT lpClipRect, LPSTR lpString,
+                                    WORD wCount, LPFONTINFO lpFontInfo, LPDRAWMODE lpDrawMode, LPTEXTXFORM lpTextXForm );
+extern DWORD    WINAPI  DIB_ColorInfo( LPPDEVICE lpDestDev, DWORD dwColorin, LPPCOLOR lpPColor );
+extern VOID     WINAPI  DIB_GetPalette( WORD nStartIndex, WORD nNumEntries, RGBQUAD lpPalette );
+extern VOID     WINAPI  DIB_GetPaletteExt( WORD nStartIndex, WORD nNumEntries, RGBQUAD lpPalette, LPPDEVICE lpDIBEngine );
+extern VOID     WINAPI  DIB_GetPaletteTranslate( LPWORD lpIndexes );
+extern VOID     WINAPI  DIB_GetPaletteTranslateExt( LPWORD lpIndexes, LPPDEVICE lpDIBEngine );
+extern VOID     WINAPI  DIB_SetPalette( WORD nStartIndex, WORD nNumEntries, LPVOID lpPalette );
+extern VOID     WINAPI  DIB_SetPaletteExt( WORD nStartIndex, WORD nNumEntries, LPVOID lpPalette, LPPDEVICE lpDIBEngine );
+extern VOID     WINAPI  DIB_SetPaletteTranslate( LPWORD lpIndexes );
+extern VOID     WINAPI  DIB_SetPaletteTranslateExt( LPWORD lpIndexes, LPPDEVICE lpDIBEngine );
+extern VOID     WINAPI  DIB_UpdateColorsExt( WORD wStartX, WORD wStart, WORD wExtX, WORD wExtY,
+                                             LPWORD lpTranslate, LPPDEVICE lpDIBEngine );
+extern VOID     WINAPI  DIB_SetCursorExt( LPPDEVICE lpDevice, LPVOID lpCursorShape );
+extern VOID     WINAPI  DIB_CheckCursorExt( LPPDEVICE lpDevice );
+extern VOID     WINAPI  DIB_MoveCursorExt( LPPDEVICE lpDevice, WORD absX, WORD absY );
+extern VOID     WINAPI  DIB_Inquire( LPVOID lpCursorInfo );
+extern VOID     WINAPI  DIB_BeginAccess( LPPDEVICE lpDevice, WORD wLeft, WORD wTop, WORD wRight, WORD wBottom, WORD wFlags );
+extern VOID     WINAPI  DIB_EndAccess( LPPDEVICE lpDevice, WORD wFlags );
+extern WORD     WINAPI  DIB_CreateDIBitmap( void );
+extern WORD     WINAPI  DIB_DeviceBitmap( LPPDEVICE lpDestDev, WORD wCommand, LPBITMAP lpBitmap, LPSTR lpBits );
+extern WORD     WINAPI  DIB_DeviceMode( HWND hWnd, HINSTANCE hInst, LPVOID lpDeviceType, LPVOID lpOutputFile );
+extern UINT     WINAPI  DIB_Enable( LPPDEVICE lpDevice, WORD wStyle, LPSTR lpDeviceType, LPSTR lpOutputFile, LPVOID lpStuff );
+extern VOID     WINAPI  DIB_Disable( LPPDEVICE lpDestDev );
+extern WORD     WINAPI  DIB_EnumDFonts( LPPDEVICE lpDestDev, LPSTR lpFaceName, FARPROC lpCallbackFunc, LPVOID lpClientData );
+extern WORD     WINAPI  DIB_SetAttribute( LPPDEVICE lpDevice, WORD wStateNum, WORD wIndex, DWORD dwAttribute );
+
+
+/* WARNING: CreateDIBPDevice returns the result in EAX, not DX:AX! */
+extern DWORD WINAPI CreateDIBPDevice( LPBITMAPINFO lpInfo, LPPDEVICE lpDevice, LPVOID lpBits, WORD wFlags );
+
+#define FB_ACCESS	    0x0001
+#define CURSOREXCLUDE	0x0008
+
+#define GREY_BIT        0x40    /* Physical color MSB. */
+
+/* DIB Engine Color Table entry. A lot like RGBQUAD. */
+typedef struct {
+    BYTE    dceBlue;
+    BYTE    dceGreen;
+    BYTE    dceRed;
+    BYTE    dceFlags;
+} DIBColorEntry;
+
+/* DIBColorEntry.dceFlags */
+#define NONSTATIC       0x80	  
+#define MAPTOWHITE      0x01	  
+
+
+/* DIB Engine Physical Object Definitions */
+
+typedef struct {
+    WORD    dpPenStyle;
+    BYTE    dpPenFlags;
+    BYTE    dpPenBpp;
+    DWORD   dpPenMono;
+    DWORD   dpPenColor;
+} DIB_Pen;
+
+typedef struct {
+    BYTE    dp1BrushFlags;              /* Accelerator for solids            */
+    BYTE    dp1BrushBpp;                /* Brush Bits per pixel format       */
+    WORD    dp1BrushStyle;              /* Style of the brush                */
+    DWORD   dp1FgColor;                 /* Physical fg color                 */
+    WORD    dp1Hatch;                   /* Hatching style                    */
+    DWORD   dp1BgColor;                 /* Physical bg color                 */
+    BYTE    dp1BrushMono[BRUSHSIZE*4];  /* Mono portion                      */
+    BYTE    dp1BrushMask[BRUSHSIZE*4];  /* transparency mask (hatch pattern) */
+    BYTE    dp1BrushBits[BRUSHSIZE*4];  /* 8 rows, 8 columns of 1 bit/pixel  */
+} DIB_Brush1;
+
+typedef struct {
+    BYTE    dp4BrushFlags;              /* Accelerator for solids            */
+    BYTE    dp4BrushBpp;                /* Brush Bits per pixel format       */
+    WORD    dp4BrushStyle;              /* Style of the brush                */
+    DWORD   dp4FgColor;                 /* Physical fg color                 */
+    WORD    dp4Hatch;                   /* Hatching style                    */
+    DWORD   dp4BgColor;                 /* Physical bg color                 */
+    BYTE    dp4BrushMono[BRUSHSIZE*4];  /* Mono portion                      */
+    BYTE    dp4BrushMask[BRUSHSIZE*4];  /* transparency mask (hatch pattern) */
+    BYTE    dp4BrushBits[BRUSHSIZE*4];  /* 8 rows, 8 columns of 4 bit/pixel  */
+} DIB_Brush4;
+
+typedef struct {
+    BYTE    dp8BrushFlags;              /* Accelerator for solids            */
+    BYTE    dp8BrushBpp;                /* Brush Bits per pixel format       */
+    WORD    dp8BrushStyle;              /* Style of the brush                */
+    DWORD   dp8FgColor;                 /* Physical fg color                 */
+    WORD    dp8Hatch;                   /* Hatching style                    */
+    DWORD   dp8BgColor;                 /* Physical bg color                 */
+    BYTE    dp8BrushMono[BRUSHSIZE*4];  /* Mono portion                      */
+    BYTE    dp8BrushMask[BRUSHSIZE*4];  /* transparency mask (hatch pattern) */
+    BYTE    dp8BrushBits[BRUSHSIZE*8];  /* 8 rows,8 columns of 8 bit/pixel   */
+} DIB_Brush8;
+
+typedef struct {
+    BYTE    dp16BrushFlags;             /* Accelerator for solids            */
+    BYTE    dp16BrushBpp;               /* Brush Bits per pixel format       */
+    WORD    dp16BrushStyle;             /* Style of the brush                */
+    DWORD   dp16FgColor;                /* Physical fg color                 */
+    WORD    dp16Hatch;                  /* Hatching style                    */
+    DWORD   dp16BgColor;                /* Physical bg color                 */
+    BYTE    dp16BrushMono[BRUSHSIZE*4]; /* Mono portion                      */
+    BYTE    dp16BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+    BYTE    dp16BrushBits[BRUSHSIZE*16];/* 8 rows,8 columns of 16 bit/pixel  */
+} DIB_Brush16;
+
+typedef struct {
+    BYTE    dp24BrushFlags;             /* Accelerator for solids            */
+    BYTE    dp24BrushBpp;               /* Brush Bits per pixel format       */
+    WORD    dp24BrushStyle;             /* Style of the brush                */
+    DWORD   dp24FgColor;                /* Physical fg color                 */
+    WORD    dp24Hatch;                  /* Hatching style                    */
+    DWORD   dp24BgColor;                /* Physical bg color                 */
+    BYTE    dp24BrushMono[BRUSHSIZE*4]; /* Mono portion                      */
+    BYTE    dp24BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+    BYTE    dp24BrushBits[BRUSHSIZE*24];/* 8 rows,8 columns of 24 bit/pixel  */
+} DIB_Brush24;
+
+typedef struct {
+    BYTE    dp32BrushFlags;             /* Accelerator for solids            */
+    BYTE    dp32BrushBpp;               /* Brush Bits per pixel format       */
+    WORD    dp32BrushStyle;             /* Style of the brush                */
+    DWORD   dp32FgColor;                /* Physical fg color                 */
+    WORD    dp32Hatch;                  /* Hatching style                    */
+    DWORD   dp32BgColor;                /* Physical bg color                 */
+    BYTE    dp32BrushMono[BRUSHSIZE*4]; /* Mono portion                      */
+    BYTE    dp32BrushMask[BRUSHSIZE*4]; /* transparency mask (hatch pattern) */
+    BYTE    dp32BrushBits[BRUSHSIZE*32];/* 8 rows,8 columns of 32 bit/pixel  */
+} DIB_Brush32;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/dibeng.lbc	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,46 @@
+++DIB_BitBlt.DIBENG.1
+++DIB_ColorInfo.DIBENG.2
+++DIB_Control.DIBENG.3
+++DIB_Disable.DIBENG.4
+++DIB_Enable.DIBENG.5
+++DIB_EnumDFonts.DIBENG.6
+++DIB_EnumObj.DIBENG.7
+++DIB_Output.DIBENG.8
+++DIB_Pixel.DIBENG.9
+++DIB_RealizeObject.DIBENG.10
+++DIB_StrBlt.DIBENG.11
+++DIB_ScanLR.DIBENG.12
+++DIB_DeviceMode.DIBENG.13
+++DIB_ExtTextOut.DIBENG.14
+++DIB_GetCharWidth.DIBENG.15
+++DIB_DeviceBitmap.DIBENG.16
+++DIB_FastBorder.DIBENG.17
+++DIB_SetAttribute.DIBENG.18
+++DIB_DibBlt.DIBENG.19
+++DIB_CreateDIBitmap.DIBENG.20
+++DIB_DibToDevice.DIBENG.21
+++DIB_SetPalette.DIBENG.22
+++DIB_GetPalette.DIBENG.23
+++DIB_SetPaletteTranslate.DIBENG.24
+++DIB_GetPaletteTranslate.DIBENG.25
+++DIB_UpdateColors.DIBENG.26
+++DIB_StretchBlt.DIBENG.27
+++DIB_StretchDIBits.DIBENG.28
+++DIB_SelectBitmap.DIBENG.29
+++DIB_BitmapBits.DIBENG.30
+++DIB_Inquire.DIBENG.101
+++DIB_SetCursorExt.DIBENG.102
+++DIB_MoveCursorExt.DIBENG.103
+++DIB_CheckCursorExt.DIBENG.104
+++DIB_BeginAccess.DIBENG.105
+++DIB_EndAccess.DIBENG.106
+++CreateDIBPDevice.DIBENG.300
+++DIB_RealizeObjectExt.DIBENG.400
+++DIB_DibBltExt.DIBENG.401
+++DIB_EnumObjExt.DIBENG.402
+++DIB_ExtTextOutExt.DIBENG.403
+++DIB_UpdateColorsExt.DIBENG.404
+++DIB_SetPaletteExt.DIBENG.405
+++DIB_GetPaletteExt.DIBENG.406
+++DIB_SetPaletteTranslateExt.DIBENG.407
+++DIB_GetPaletteTranslateExt.DIBENG.408
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/gdidefs.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,828 @@
+
+/* Definitions for GDI drivers. */
+
+/* Physical Bitmap structure. */
+typedef struct {
+    short int           bmType;
+    unsigned short int  bmWidth;
+    unsigned short int  bmHeight;
+    unsigned short int  bmWidthBytes;
+    BYTE                bmPlanes;
+    BYTE                bmBitsPixel;
+    BYTE FAR            *bmBits;
+    unsigned long int   bmWidthPlanes;
+    BYTE FAR            *bmlpPDevice;
+    unsigned short int  bmSegmentIndex;
+    unsigned short int  bmScanSegment;
+    unsigned short int  bmFillBytes;
+    unsigned short int  futureUse4;
+    unsigned short int  futureUse5;
+} BITMAP;
+
+/* DIB structs also defined in windows.h. */
+typedef struct {
+    DWORD   bcSize;
+    WORD    bcWidth;
+    WORD    bcHeight;
+    WORD    bcPlanes;
+    WORD    bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;
+
+typedef struct {
+    DWORD   biSize;
+    DWORD   biWidth;
+    DWORD   biHeight;
+    WORD    biPlanes;
+    WORD    biBitCount;
+    DWORD   biCompression;
+    DWORD   biSizeImage;
+    DWORD   biXPelsPerMeter;
+    DWORD   biYPelsPerMeter;
+    DWORD   biClrUsed;
+    DWORD   biClrImportant;
+} BITMAPINFOHEADER;
+
+typedef BITMAPINFOHEADER FAR *LPBITMAPINFOHEADER;
+typedef BITMAPINFOHEADER *PBITMAPINFOHEADER;
+
+typedef struct {
+    BYTE    rgbtBlue;
+    BYTE    rgbtGreen;
+    BYTE    rgbtRed;
+} RGBTRIPLE;
+
+typedef struct {
+    BYTE    rgbBlue;
+    BYTE    rgbGreen;
+    BYTE    rgbRed;
+    BYTE    rgbReserved;
+} RGBQUAD;
+
+/* ICM Color Definitions */
+typedef long    FXPT16DOT16, FAR *LPFXPT16DOT16;
+typedef long    FXPT2DOT30,  FAR *LPFXPT2DOT30;
+
+typedef struct tagCIEXYZ
+{
+    FXPT2DOT30  ciexyzX;
+    FXPT2DOT30  ciexyzY;
+    FXPT2DOT30  ciexyzZ;
+} CIEXYZ;
+typedef CIEXYZ  FAR *LPCIEXYZ;
+
+typedef struct tagICEXYZTRIPLE
+{
+    CIEXYZ  ciexyzRed;
+    CIEXYZ  ciexyzGreen;
+    CIEXYZ  ciexyzBlue;
+} CIEXYZTRIPLE;
+typedef CIEXYZTRIPLE FAR    *LPCIEXYZTRIPLE;
+
+typedef struct { 
+    BITMAPCOREHEADER    bmciHeader;
+    RGBQUAD             bmciColors[1];
+} BITMAPCOREINFO;
+
+typedef BITMAPCOREINFO FAR *LPBITMAPCOREINFO;
+typedef BITMAPCOREINFO *PBITMAPCOREINFO;
+
+typedef struct { 
+    BITMAPINFOHEADER    bmiHeader;
+    RGBQUAD             bmiColors[1];
+} BITMAPINFO;
+
+typedef BITMAPINFO FAR *LPBITMAPINFO;
+typedef BITMAPINFO *PBITMAPINFO;
+
+typedef struct {
+    DWORD           bV4Size;
+    LONG            bV4Width;
+    LONG            bV4Height;
+    WORD            bV4Planes;
+    WORD            bV4BitCount;
+    DWORD           bV4V4Compression;
+    DWORD           bV4SizeImage;
+    LONG            bV4XPelsPerMeter;
+    LONG            bV4YPelsPerMeter;
+    DWORD           bV4ClrUsed;
+    DWORD           bV4ClrImportant;
+    DWORD           bV4RedMask;
+    DWORD           bV4GreenMask;
+    DWORD           bV4BlueMask;
+    DWORD           bV4AlphaMask;
+    DWORD           bV4CSType;
+    CIEXYZTRIPLE    bV4Endpoints;
+    DWORD           bV4GammaRed;
+    DWORD           bV4GammaGreen;
+    DWORD           bV4GammaBlue;
+} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER;
+
+typedef struct { 
+    BITMAPV4HEADER  bmv4Header;
+    RGBQUAD         bmv4Colors[1];
+} BITMAPV4INFO;
+
+typedef BITMAPV4INFO FAR *LPBITMAPV4INFO;
+typedef BITMAPV4INFO *PBITMAPV4INFO;
+
+/* currently, if the low byte of biCompression is non zero, 
+ * it must be one of following */
+
+#define BI_RGB              0x00
+#define BI_RLE8             0x01
+#define BI_RLE4             0x02
+#define BI_BITFIELDS        0x03
+
+#define BITMAP_SELECTED     0x01
+#define BITMAP_64K          0x01
+
+#define DIBSIGNATURE        0x4944
+
+/* Point types are optional. */
+#ifndef NOPTRC
+
+typedef     struct {
+    short int xcoord;
+    short int ycoord;
+} PTTYPE;
+typedef PTTYPE *PPOINT;
+typedef PTTYPE FAR *LPPOINT;
+
+#define     POINT   PTTYPE
+
+typedef struct {
+    short int   left;
+    short int   top;
+    short int   right;
+    short int   bottom;
+} RECT;
+typedef RECT    *PRECT;
+
+#endif
+
+typedef struct {
+    PTTYPE  min;
+    PTTYPE  ext;
+} BOXTYPE;
+typedef RECT FAR    *LPRECT;
+
+/* Object definitions used by GDI support routines written in C */
+
+#define OBJ_PEN         1
+#define OBJ_BRUSH       2
+#define OBJ_FONT        3
+
+typedef struct {
+    unsigned short int  lbStyle;
+    unsigned long int   lbColor;
+    unsigned short int  lbHatch;
+    unsigned long int   lbBkColor;
+    unsigned long int   lbhcmXform;
+} LOGBRUSH;
+
+#define lbPattern       lbColor
+
+/* Brush Style definitions. */
+#define     BS_SOLID            0
+#define     BS_HOLLOW           1
+#define     BS_HATCHED          2
+#define     BS_PATTERN          3
+
+#define     MaxBrushStyle       3
+
+/* Hatch Style definitions. */
+#define     HS_HORIZONTAL       0       /* ----- */
+#define     HS_VERTICAL         1       /* ||||| */
+#define     HS_FDIAGONAL        2       /* ///// */
+#define     HS_BDIAGONAL        3       /* \\\\\ */
+#define     HS_CROSS            4       /* +++++ */
+#define     HS_DIAGCROSS        5       /* xxxxx */
+
+#define     MaxHatchStyle       5
+
+
+/* Logical Pen Structure. */
+typedef struct {
+    unsigned short int lopnStyle;
+    PTTYPE             lopnWidth;
+    unsigned long int  lopnColor;
+    unsigned short int lopnStyle2;
+    unsigned long int  lopnhcmXform;
+} LOGPEN;
+
+/* Line Style definitions. */
+#define     LS_SOLID            0
+#define     LS_DASHED           1
+#define     LS_DOTTED           2
+#define     LS_DOTDASHED        3
+#define     LS_DASHDOTDOT       4
+#define     LS_NOLINE           5
+#define     LS_INSIDEFRAME      6
+#define     MaxLineStyle        LS_NOLINE
+
+#define     LS_ENDCAP_FLAT      0x01
+#define     LS_ENDCAP_ROUND     0x02
+#define     LS_ENDCAP_SQUARE    0x04
+#define     LS_JOIN_BEVEL       0x08
+#define     LS_JOIN_MITER       0x10
+#define     LS_JOIN_ROUND       0x20
+
+
+/* The size to allocate for the lfFaceName field in the logical font. */
+#ifndef     LF_FACESIZE
+#define     LF_FACESIZE     32
+#endif
+
+/* Various constants for defining a logical font. */
+#define OUT_DEFAULT_PRECIS      0
+#define OUT_STRING_PRECIS       1
+#define OUT_CHARACTER_PRECIS    2
+#define OUT_STROKE_PRECIS       3
+#define OUT_TT_PRECIS           4
+#define OUT_DEVICE_PRECIS       5
+#define OUT_RASTER_PRECIS       6
+#define OUT_TT_ONLY_PRECIS      7
+
+#define CLIP_DEFAULT_PRECIS     0
+#define CLIP_CHARACTER_PRECIS   1
+#define CLIP_STROKE_PRECIS      2
+#define CLIP_MASK               0x0F
+#define CLIP_LH_ANGLES          0x10
+#define CLIP_TT_ALWAYS          0x20
+#define CLIP_EMBEDDED           0x80
+
+#define DEFAULT_QUALITY         0
+#define DRAFT_QUALITY           1
+#define PROOF_QUALITY           2
+
+#define DEFAULT_PITCH           0
+#define FIXED_PITCH             1
+#define VARIABLE_PITCH          2
+
+#define ANSI_CHARSET            0
+#define DEFAULT_CHARSET         1
+#define SYMBOL_CHARSET          2
+#define MAC_CHARSET             77
+#define SHIFTJIS_CHARSET        128
+#define HANGEUL_CHARSET         129
+#define CHINESEBIG5_CHARSET     136
+#define OEM_CHARSET             255
+
+
+/*      GDI font families.                                              */
+#define FF_DONTCARE     (0<<4)  /* Don't care or don't know.            */
+#define FF_ROMAN        (1<<4)  /* Variable stroke width, serifed.      */
+                                /* Times Roman, Century Schoolbook, etc.*/
+#define FF_SWISS        (2<<4)  /* Variable stroke width, sans-serifed. */
+                                /* Helvetica, Swiss, etc.               */
+#define FF_MODERN       (3<<4)  /* Constant stroke width, serifed or sans-serifed. */
+                                /* Pica, Elite, Courier, etc.           */
+#define FF_SCRIPT       (4<<4)  /* Cursive, etc.                        */
+#define FF_DECORATIVE   (5<<4)  /* Old English, etc.                    */
+
+
+/* Font weights lightest to heaviest. */
+#define FW_DONTCARE             0
+#define FW_THIN                 100
+#define FW_EXTRALIGHT           200
+#define FW_LIGHT                300
+#define FW_NORMAL               400
+#define FW_MEDIUM               500
+#define FW_SEMIBOLD             600
+#define FW_BOLD                 700
+#define FW_EXTRABOLD            800
+#define FW_HEAVY                900
+
+#define FW_ULTRALIGHT           FW_EXTRALIGHT
+#define FW_REGULAR              FW_NORMAL
+#define FW_DEMIBOLD             FW_SEMIBOLD
+#define FW_ULTRABOLD            FW_EXTRABOLD
+#define FW_BLACK                FW_HEAVY
+
+/* Enumeration font types. */
+#define     RASTER_FONTTYPE         1
+#define     DEVICE_FONTTYPE         2
+
+
+
+typedef     struct  {
+    short int   lfHeight;
+    short int   lfWidth;
+    short int   lfEscapement;
+    short int   lfOrientation;
+    short int   lfWeight;
+    BYTE        lfItalic;
+    BYTE        lfUnderline;
+    BYTE        lfStrikeOut;
+    BYTE        lfCharSet;
+    BYTE        lfOutPrecision;
+    BYTE        lfClipPrecision;
+    BYTE        lfQuality;
+    BYTE        lfPitchAndFamily;
+    BYTE        lfFaceName[LF_FACESIZE];
+} LOGFONT;
+
+
+#define     InquireInfo     0x01        /* Inquire Device GDI Info         */
+#define     EnableDevice    0x00        /* Enable Device                   */
+#define     InfoContext     0x8000      /* Inquire/Enable for info context */
+
+/* Device Technology types */
+#define     DT_PLOTTER          0       /* Vector plotter          */
+#define     DT_RASDISPLAY       1       /* Raster display          */
+#define     DT_RASPRINTER       2       /* Raster printer          */
+#define     DT_RASCAMERA        3       /* Raster camera           */
+#define     DT_CHARSTREAM       4       /* Character-stream, PLP   */
+#define     DT_METAFILE         5       /* Metafile, VDM           */
+#define     DT_DISPFILE         6       /* Display-file            */
+#define     DT_JUMBO            11      /* SPAG LJ cool thing      */
+
+/* Curve Capabilities */
+#define     CC_NONE         0x0000      /* Curves not supported    */
+#define     CC_CIRCLES      0x0001      /* Can do circles          */
+#define     CC_PIE          0x0002      /* Can do pie wedges       */
+#define     CC_CHORD        0x0004      /* Can do chord arcs       */
+#define     CC_ELLIPSES     0x0008      /* Can do ellipese         */
+#define     CC_WIDE         0x0010      /* Can do wide lines       */
+#define     CC_STYLED       0x0020      /* Can do styled lines     */
+#define     CC_WIDESTYLED   0x0040      /* Can do wide styled lines*/
+#define     CC_INTERIORS    0x0080      /* Can do interiors        */
+#define     CC_ROUNDRECT    0x0100      /* Can do round rectangles */
+#define     CC_POLYBEZIER   0x0200      /* Can do polybeziers      */
+
+/* Line Capabilities */
+#define     LC_NONE         0x0000      /* Lines not supported     */
+#define     LC_POLYSCANLINE 0x0001      /* Poly Scanlines supported*/
+#define     LC_POLYLINE     0x0002      /* Can do polylines        */
+#define     LC_MARKER       0x0004      /* Can do markers          */
+#define     LC_POLYMARKER   0x0008      /* Can do polymarkers      */
+#define     LC_WIDE         0x0010      /* Can do wide lines       */
+#define     LC_STYLED       0x0020      /* Can do styled lines     */
+#define     LC_WIDESTYLED   0x0040      /* Can do wide styled lines*/
+#define     LC_INTERIORS    0x0080      /* Can do interiors        */
+
+/* Polygonal Capabilities */
+#define     PC_NONE         0x0000      /* Polygonals not supported*/
+#define     PC_ALTPOLYGON   0x0001      /* Can do even odd polygons*/
+#define     PC_POLYGON      0x0001      /* old name for ALTPOLYGON */
+#define     PC_RECTANGLE    0x0002      /* Can do rectangles       */
+#define     PC_WINDPOLYGON  0x0004      /* Can do winding polygons */
+#define     PC_TRAPEZOID    0x0004      /* old name for WINDPOLYGON*/
+#define     PC_SCANLINE     0x0008      /* Can do scanlines        */
+#define     PC_WIDE         0x0010      /* Can do wide borders     */
+#define     PC_STYLED       0x0020      /* Can do styled borders   */
+#define     PC_WIDESTYLED   0x0040      /* Can do wide styled borders*/
+#define     PC_INTERIORS    0x0080      /* Can do interiors        */
+#define     PC_POLYPOLYGON  0x0100      /* Can do PolyPolygons     */
+
+/* Clipping Capabilities */
+#define     CP_NONE         0x0000      /* no clipping of Output   */
+#define     CP_RECTANGLE    0x0001      /* Output clipped to Rects */
+#define     CP_REGION       0x0002      /* not supported           */
+#define     CP_REGION32     0x0004      /* Output clipped to regions */
+
+/* Text Capabilities */
+#define TC_OP_CHARACTER 0x0001          /* Can do OutputPrecision    CHARACTER      */
+#define TC_OP_STROKE    0x0002          /* Can do OutputPrecision    STROKE         */
+#define TC_CP_STROKE    0x0004          /* Can do ClipPrecision      STROKE         */
+#define TC_CR_90        0x0008          /* Can do CharRotAbility     90             */
+#define TC_CR_ANY       0x0010          /* Can do CharRotAbility     ANY            */
+#define TC_SF_X_YINDEP  0x0020          /* Can do ScaleFreedom       X_YINDEPENDENT */
+#define TC_SA_DOUBLE    0x0040          /* Can do ScaleAbility       DOUBLE         */
+#define TC_SA_INTEGER   0x0080          /* Can do ScaleAbility       INTEGER        */
+#define TC_SA_CONTIN    0x0100          /* Can do ScaleAbility       CONTINUOUS     */
+#define TC_EA_DOUBLE    0x0200          /* Can do EmboldenAbility    DOUBLE         */
+#define TC_IA_ABLE      0x0400          /* Can do ItalisizeAbility   ABLE           */
+#define TC_UA_ABLE      0x0800          /* Can do UnderlineAbility   ABLE           */
+#define TC_SO_ABLE      0x1000          /* Can do StrikeOutAbility   ABLE           */
+#define TC_RA_ABLE      0x2000          /* Can do RasterFontAble     ABLE           */
+#define TC_VA_ABLE      0x4000          /* Can do VectorFontAble     ABLE           */
+#define TC_RESERVED     0x8000          /* Reserved. Must be returned zero.        */
+
+/* Raster Capabilities */
+#define RC_NONE         0x0000          /* No Raster Capabilities       */
+#define RC_BITBLT       0x0001          /* Can do bitblt                */
+#define RC_BANDING      0x0002          /* Requires banding support     */
+#define RC_SCALING      0x0004          /* does scaling while banding   */
+#define RC_BITMAP64     0x0008          /* supports >64k bitmaps        */
+#define RC_GDI20_OUTPUT 0x0010          /* has 2.0 output calls         */
+#define RC_GDI20_STATE  0x0020          /* dc has a state block         */
+#define RC_SAVEBITMAP   0x0040          /* can save bitmaps locally     */
+#define RC_DI_BITMAP    0x0080          /* can do DIBs                  */
+#define RC_PALETTE      0x0100          /* can do color pal management  */
+#define RC_DIBTODEV     0x0200          /* can do SetDIBitsToDevice     */
+#define RC_BIGFONT      0x0400          /* can do BIGFONTs              */
+#define RC_STRETCHBLT   0x0800          /* can do StretchBlt            */
+#define RC_FLOODFILL    0x1000          /* can do FloodFill             */
+#define RC_STRETCHDIB   0x2000          /* can do StretchDIBits         */
+#define RC_OP_DX_OUTPUT 0x4000          /* can do smart ExtTextOut w/dx */
+#define RC_DEVBITS      0x8000          /* supports device bitmaps      */
+
+/* DC Management Flags */
+#define DC_SPDevice     0000001     /* Seperate PDevice required per device/filename */
+#define DC_1PDevice     0000002     /* Only 1 PDevice allowed per device/filename    */
+#define DC_IgnoreDFNP   0000004     /* Ignore device/filename pairs when matching    */
+
+/* dpCaps1 capability bits  */
+#define C1_TRANSPARENT  0x0001      /* supports transparency                */
+#define TC_TT_ABLE      0x0002      /* can do TT through DDI or brute       */
+#define C1_TT_CR_ANY    0x0004      /* can do rotated TT fonts              */
+#define C1_EMF_COMPLIANT 0x0008     /* Win95 - supports metafile spooling   */
+#define C1_DIBENGINE    0x0010      /* DIB Engine compliant driver          */
+#define C1_GAMMA_RAMP   0x0020      /* supports gamma ramp setting          */
+#define C1_ICM          0x0040      /* does some form of ICM support        */
+#define C1_REINIT_ABLE  0x0080      /* Driver supports ReEnable             */
+#define C1_GLYPH_INDEX  0x0100      /* Driver supports glyph index fonts    */
+#define C1_BIT_PACKED   0x0200      /* Supports bit-packed glyphs           */
+#define C1_BYTE_PACKED  0x0400      /* Supports byte-packed glyphs          */
+#define C1_COLORCURSOR  0x0800      /* Driver supports color_cursors and async SetCursor */
+#define C1_CMYK_ABLE    0x1000      /* Driver supports CMYK ColorRefs       */
+#define C1_SLOW_CARD    0x2000      /* Little or no acceleration (VGA, etc.)*/
+
+/* dpCapsFE capability bits */
+#define FEC_TT_DBCS     0x0020      /* can output DBCS TT fonts correctly   */
+#define FEC_WIFE_ABLE   0x0080      /* can handle WIFE font as Engine font  */
+
+typedef struct {
+    short int           dpVersion;
+    short int           dpTechnology;
+    short int           dpHorzSize;
+    short int           dpVertSize;
+    short int           dpHorzRes;
+    short int           dpVertRes;
+    short int           dpBitsPixel;
+    short int           dpPlanes;
+    short int           dpNumBrushes;
+    short int           dpNumPens;
+    short int           dpCapsFE;
+    short int           dpNumFonts;
+    short int           dpNumColors;
+    short int           dpDEVICEsize;
+    unsigned short int  dpCurves;
+    unsigned short int  dpLines;
+    unsigned short int  dpPolygonals;
+    unsigned short int  dpText;
+    unsigned short int  dpClip;
+    unsigned short int  dpRaster;
+    short int           dpAspectX;
+    short int           dpAspectY;
+    short int           dpAspectXY;
+    short int           dpStyleLen;
+    PTTYPE              dpMLoWin;
+    PTTYPE              dpMLoVpt;
+    PTTYPE              dpMHiWin;
+    PTTYPE              dpMHiVpt;
+    PTTYPE              dpELoWin;
+    PTTYPE              dpELoVpt;
+    PTTYPE              dpEHiWin;
+    PTTYPE              dpEHiVpt;
+    PTTYPE              dpTwpWin;
+    PTTYPE              dpTwpVpt;
+    short int           dpLogPixelsX;
+    short int           dpLogPixelsY;
+    short int           dpDCManage;
+    unsigned short int  dpCaps1;
+    short int           futureuse4;
+    short int           futureuse5;
+    short int           futureuse6;
+    short int           futureuse7;
+    WORD                dpNumPalReg;
+    WORD                dpPalReserved;
+    WORD                dpColorRes;
+} GDIINFO;
+
+/* This bit in the dfType field signals that the dfBitsOffset field is an
+   absolute memory address and should not be altered. */
+#define PF_BITS_IS_ADDRESS  4
+
+/* This bit in the dfType field signals that the font is device realized. */
+#define PF_DEVICE_REALIZED  0x80
+
+/* These bits in the dfType give the fonttype -
+       raster, vector, other1, other2. */
+#define PF_RASTER_TYPE      0
+#define PF_VECTOR_TYPE      1
+#define PF_OTHER1_TYPE      2
+#define PF_OTHER2_TYPE      3
+#define PF_GLYPH_INDEX   0x20
+#define PF_WIFE_TYPE     0x08
+
+/* Glyph types for EngineGetGlyphBmp */
+#define EGB_BITMAP          1
+#define EGB_OUTLINE         2
+#define EGB_GRAY2_BITMAP    8
+#define EGB_GRAY4_BITMAP    9
+#define EGB_GRAY8_BITMAP   10
+
+
+/* The size to allocate for the dfMaps field in the physical font. */
+#ifndef     DF_MAPSIZE
+#define     DF_MAPSIZE      1
+#endif
+
+/* Font structure. */
+typedef     struct  {
+    short int           dfType;
+    short int           dfPoints;
+    short int           dfVertRes;
+    short int           dfHorizRes;
+    short int           dfAscent;
+    short int           dfInternalLeading;
+    short int           dfExternalLeading;
+    BYTE                dfItalic;
+    BYTE                dfUnderline;
+    BYTE                dfStrikeOut;
+    short int           dfWeight;
+    BYTE                dfCharSet;
+    short int           dfPixWidth;
+    short int           dfPixHeight;
+    BYTE                dfPitchAndFamily;
+    short int           dfAvgWidth;
+    short int           dfMaxWidth;
+    BYTE                dfFirstChar;
+    BYTE                dfLastChar;
+    BYTE                dfDefaultChar;
+    BYTE                dfBreakChar;
+    short int           dfWidthBytes;
+    unsigned long int   dfDevice;
+    unsigned long int   dfFace;
+    unsigned long int   dfBitsPointer;
+    unsigned long int   dfBitsOffset;
+    BYTE                dfReservedByte;
+    unsigned short      dfMaps[DF_MAPSIZE];
+} FONTINFO;
+
+
+typedef struct {
+    short int           erType;
+    short int           erPoints;
+    short int           erVertRes;
+    short int           erHorizRes;
+    short int           erAscent;
+    short int           erInternalLeading;
+    short int           erExternalLeading;
+    BYTE                erItalic;
+    BYTE                erUnderline;
+    BYTE                erStrikeOut;
+    short int           erWeight;
+    BYTE                erCharSet;
+    short int           erPixWidth;
+    short int           erPixHeight;
+    BYTE                erPitchAndFamily;
+    short int           erAvgWidth;
+    short int           erMaxWidth;
+    BYTE                erFirstChar;
+    BYTE                erLastChar;
+    BYTE                erDefaultChar;
+    BYTE                erBreakChar;
+    short int           erWidthBytes;
+    unsigned long int   erDevice;
+    unsigned long int   erFace;
+    unsigned long int   erBitsPointer;
+    unsigned long int   erBitsOffset;
+    BYTE                erReservedByte;
+    short int           erUnderlinePos;
+    short int           erUnderlineThick;
+    short int           erStrikeoutPos;
+    short int           erStrikeoutThick;
+} SCALABLEFONTINFO;
+
+
+typedef struct {
+    short int           ftHeight;
+    short int           ftWidth;
+    short int           ftEscapement;
+    short int           ftOrientation;
+    short int           ftWeight;
+    BYTE                ftItalic;
+    BYTE                ftUnderline;
+    BYTE                ftStrikeOut;
+    BYTE                ftOutPrecision;
+    BYTE                ftClipPrecision;
+    unsigned short int  ftAccelerator;
+    short int           ftOverhang;
+} TEXTXFORM;
+
+
+typedef struct {
+    short int   tmHeight;
+    short int   tmAscent;
+    short int   tmDescent;
+    short int   tmInternalLeading;
+    short int   tmExternalLeading;
+    short int   tmAveCharWidth;
+    short int   tmMaxCharWidth;
+    short int   tmWeight;
+    BYTE        tmItalic;
+    BYTE        tmUnderlined;
+    BYTE        tmStruckOut;
+    BYTE        tmFirstChar;
+    BYTE        tmLastChar;
+    BYTE        tmDefaultChar;
+    BYTE        tmBreakChar;
+    BYTE        tmPitchAndFamily;
+    BYTE        tmCharSet;
+    short int   tmOverhang;
+    short int   tmDigitizedAspectX;
+    short int   tmDigitizedAspectY;
+} TEXTMETRIC;
+
+typedef struct {
+    short int           Rop2;
+    short int           bkMode;
+    unsigned long int   bkColor;
+    unsigned long int   TextColor;
+    short int           TBreakExtra;
+    short int           BreakExtra;
+    short int           BreakErr;
+    short int           BreakRem;
+    short int           BreakCount;
+    short int           CharExtra;
+    unsigned long int   LbkColor;
+    unsigned long int   LTextColor;
+    DWORD               ICMCXform;
+    short               StretchBltMode;
+    DWORD               eMiterLimit;
+} DRAWMODE;
+
+
+/* Background Mode definitions. */
+#define TRANSPARENT             1
+#define OPAQUE                  2
+
+#define BKMODE_TRANSPARENT      1
+#define BKMODE_OPAQUE           2
+#define BKMODE_LEVEL1           3
+#define BKMODE_LEVEL2           4
+#define BKMODE_LEVEL3           5
+#define BKMODE_TRANSLATE        6
+
+/* StretchBlt Mode definitions. */
+#define STRETCH_ANDSCANS        1
+#define STRETCH_ORSCANS         2
+#define STRETCH_DELETESCANS     3
+#define STRETCH_HALFTONE        4
+
+#define SBM_BLACKONWHITE        STRETCH_ANDSCANS
+#define SBM_WHITEONBLACK        STRETCH_ORSCANS
+#define SBM_COLORONCOLOR        STRETCH_DELETESCANS
+#define SBM_HALFTONE            STRETCH_HALFTONE
+
+typedef struct {
+    short int   scnPntCnt;
+    short int   scnPntTop;
+    short int   scnPntBottom;
+    short int   scnPntX[2];
+    short int   scnPntCntToo;
+} SCAN, FAR* LPSCAN;
+
+typedef struct {
+    DWORD   cbSize;
+    LPVOID  lpDestDev;
+    DWORD   nEscape;
+    DWORD   cbInput;
+    LPVOID  lpInput;
+    POINT   ptOrigin;
+    DWORD   dwUniq;
+    RECT    rcBBox;
+    DWORD   cScans;
+    LPSCAN  lpScan;
+} DRAWESCAPE, FAR* LPDRAWESCAPE;
+
+typedef struct {
+    WORD    id;
+    WORD    cbSize;
+    LPRECT  lprcClip;
+    DWORD   dwUniq;
+    RECT    rcBBox;
+    DWORD   cScans;
+    LPSCAN  lpScan;
+} REGION, FAR* LPREGION;
+
+
+/* Output Style definitions. */
+
+#define OS_POLYBEZIER       1
+#define OS_ARC              3
+#define OS_SCANLINES        4
+#define OS_POLYSCANLINE     5
+#define OS_RECTANGLE        6
+#define OS_ELLIPSE          7
+#define OS_MARKER           8
+#define OS_POLYLINE         18
+#define OS_TRAPEZOID        20
+#define OS_WINDPOLYGON      OS_TRAPEZOID
+#define OS_POLYGON          22
+#define OS_ALTPOLYGON       OS_POLYGON
+#define OS_PIE              23
+#define OS_POLYMARKER       24
+#define OS_CHORD            39
+#define OS_CIRCLE           55
+
+#define OS_POLYPOLYGON      0x4000  /* ORed with OS_WIND/ALTPOLYGON. */
+
+#define OS_BEGINNSCAN       80
+#define OS_ENDNSCAN         81
+
+#define OEM_FAILED          0x80000000L
+
+#define NEWFRAME                     1
+#define ABORTDOC                     2
+#define NEXTBAND                     3
+#define SETCOLORTABLE                4
+#define GETCOLORTABLE                5
+#define FLUSHOUTPUT                  6
+#define DRAFTMODE                    7
+#define QUERYESCSUPPORT              8
+#define SETPRINTERDC                 9          /* DDK: between GDI and Driver. */
+#define SETABORTPROC                 9          /* SDK: between application and GDI. */
+#define STARTDOC                     10
+#define ENDDOC                       11
+#define GETPHYSPAGESIZE              12
+#define GETPRINTINGOFFSET            13
+#define GETSCALINGFACTOR             14
+#define MFCOMMENT                    15
+#define GETPENWIDTH                  16
+#define SETCOPYCOUNT                 17
+#define SELECTPAPERSOURCE            18
+#define DEVICEDATA                   19
+#define PASSTHROUGH                  19
+#define GETTECHNOLGY                 20
+#define GETTECHNOLOGY                20
+#define SETLINECAP                   21
+#define SETLINEJOIN                  22
+#define SETMITERLIMIT                23
+#define BANDINFO                     24
+#define DRAWPATTERNRECT              25
+#define GETVECTORPENSIZE             26
+#define GETVECTORBRUSHSIZE           27
+#define ENABLEDUPLEX                 28
+#define GETSETPAPERBINS              29
+#define GETSETPRINTORIENT            30
+#define ENUMPAPERBINS                31
+#define SETDIBSCALING                32
+#define EPSPRINTING                  33
+#define ENUMPAPERMETRICS             34
+#define GETSETPAPERMETRICS           35
+#define GETVERSION                   36
+#define POSTSCRIPT_DATA              37
+#define POSTSCRIPT_IGNORE            38
+#define QUERYROPSUPPORT              40
+#define GETDEVICEUNITS               42
+#define RESETDEVICE                  128
+#define GETEXTENDEDTEXTMETRICS       256
+#define GETEXTENTTABLE               257
+#define GETPAIRKERNTABLE             258
+#define GETTRACKKERNTABLE            259
+#define EXTTEXTOUT                   512
+#define GETFACENAME                  513
+#define DOWNLOADFACE                 514
+#define ENABLERELATIVEWIDTHS         768
+#define ENABLEPAIRKERNING            769
+#define SETKERNTRACK                 770
+#define SETALLJUSTVALUES             771
+#define SETCHARSET                   772
+#define STRETCHBLT                   2048
+#define QUERYDIBSUPPORT              3073
+#define QDI_SETDIBITS                0x0001
+#define QDI_GETDIBITS                0x0002
+#define QDI_DIBTOSCREEN              0x0004
+#define QDI_STRETCHDIB               0x0008
+#define DCICOMMAND                   3075
+#define BEGIN_PATH                   4096
+#define CLIP_TO_PATH                 4097
+#define END_PATH                     4098
+#define EXT_DEVICE_CAPS              4099
+#define RESTORE_CTM                  4100
+#define SAVE_CTM                     4101
+#define SET_ARC_DIRECTION            4102
+#define SET_BACKGROUND_COLOR         4103
+#define SET_POLY_MODE                4104
+#define SET_SCREEN_ANGLE             4105
+#define SET_SPREAD                   4106
+#define TRANSFORM_CTM                4107
+#define SET_CLIP_BOX                 4108
+#define SET_BOUNDS                   4109
+#define OPENCHANNEL                  4110
+#define DOWNLOADHEADER               4111
+#define CLOSECHANNEL                 4112
+#define SETGDIXFORM                  4113
+#define RESETPAGE                    4114
+#define POSTSCRIPT_PASSTHROUGH       4115
+#define ENCAPSULATED_POSTSCRIPT      4116   
+
+
+typedef FONTINFO    FAR *LPFONTINFO;
+typedef DRAWMODE    FAR *LPDRAWMODE;
+typedef TEXTXFORM   FAR *LPTEXTXFORM;
+typedef TEXTMETRIC  FAR *LPTEXTMETRIC;
+typedef LOGFONT     FAR *LPLOGFONT;
+typedef LOGPEN      FAR *LPLOGPEN;
+typedef LOGBRUSH    FAR *LPLOGBRUSH;
+typedef BITMAP      FAR *LPBITMAP;
+typedef FARPROC     FAR *LPFARPROC;
+typedef GDIINFO     FAR *LPGDIINFO;
+typedef SCALABLEFONTINFO FAR * LPSCALABLEFONTINFO;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/minivdd.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,114 @@
+
+/* Functions callable via VDD's API entry point, usually called by display
+ * drivers.
+ */
+#define MINIVDD_SVC_BASE_OFFSET             0x80
+#define VDD_DRIVER_REGISTER                 (0 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_DRIVER_UNREGISTER               (1 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SAVE_DRIVER_STATE               (2 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_REGISTER_DISPLAY_DRIVER_INFO    (3 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_REGISTER_SSB_FLAGS              (4 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_GET_DISPLAY_CONFIG              (5 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_PRE_MODE_CHANGE                 (6 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_POST_MODE_CHANGE                (7 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SET_USER_FLAGS                  (8 + MINIVDD_SVC_BASE_OFFSET)
+#define VDD_SET_BUSY_FLAG_ADDR              (9 + MINIVDD_SVC_BASE_OFFSET)
+
+/* The DISPLAYINFO structure for querying Registry information. */
+typedef struct {
+    WORD    diHdrSize;
+    WORD    diInfoFlags;
+    DWORD   diDevNodeHandle;
+    char    diDriverName[16];
+    WORD    diXRes;
+    WORD    diYRes;
+    WORD    diDPI;
+    BYTE    diPlanes;
+    BYTE    diBpp;
+    WORD    diRefreshRateMax;
+    WORD    diRefreshRateMin;
+    WORD    diLowHorz;
+    WORD    diHighHorz;
+    WORD    diLowVert;
+    WORD    diHighVert;
+    DWORD   diMonitorDevNodeHandle;
+    BYTE    diHorzSyncPolarity;
+    BYTE    diVertSyncPolarity;
+} DISPLAYINFO;
+
+/* diInfoFlags */
+#define RETURNED_DATA_IS_STALE          0x001   /* VDD couldn't read Registry, data could be old. */
+#define MINIVDD_FAILED_TO_LOAD          0x002   /* MiniVDD did not load, probably bad config. */
+#define MINIVDD_CHIP_ID_DIDNT_MATCH     0x004   /* ChipID mismatch, probably bad config. */
+#define REGISTRY_BPP_NOT_VALID          0x008   /* BPP could not be read from Registry. */
+#define REGISTRY_RESOLUTION_NOT_VALID   0x010   /* Resolution could not be read from Registry. */
+#define REGISTRY_DPI_NOT_VALID          0x020   /* DPI could not be read from Registry. */
+#define MONITOR_DEVNODE_NOT_ACTIVE      0x040   /* Devnode not there, no refresh rate data. */
+#define MONITOR_INFO_NOT_VALID          0x080   /* Refresh rate data could not be read. */
+#define MONITOR_INFO_DISABLED_BY_USER   0x100   /* Refresh rate data not valid. */
+#define REFRESH_RATE_MAX_ONLY           0x200   /* Only diRefreshRateMax is valid. */
+#define CARD_VDD_LOADED_OK              0x400   /* Second MiniVDD loaded fine. */
+
+/* Funcrions callable in a mini-VDD. */
+#define REGISTER_DISPLAY_DRIVER     0
+#define GET_VDD_BANK                1
+#define SET_VDD_BANK                2
+#define RESET_BANK                  3
+#define PRE_HIRES_TO_VGA            4
+#define POST_HIRES_TO_VGA           5
+#define PRE_VGA_TO_HIRES            6
+#define POST_VGA_TO_HIRES           7
+#define SAVE_REGISTERS              8
+#define RESTORE_REGISTERS           9
+#define MODIFY_REGISTER_STATE       10
+#define ACCESS_VGA_MEMORY_MODE      11
+#define ACCESS_LINEAR_MEMORY_MODE   12
+#define ENABLE_TRAPS                13
+#define DISABLE_TRAPS               14
+#define MAKE_HARDWARE_NOT_BUSY      15
+#define VIRTUALIZE_CRTC_IN          16
+#define VIRTUALIZE_CRTC_OUT         17
+#define VIRTUALIZE_SEQUENCER_IN     18
+#define VIRTUALIZE_SEQUENCER_OUT    19
+#define VIRTUALIZE_GCR_IN           20
+#define VIRTUALIZE_GCR_OUT          21
+#define SET_LATCH_BANK              22
+#define RESET_LATCH_BANK            23
+#define SAVE_LATCHES                24
+#define RESTORE_LATCHES             25
+#define DISPLAY_DRIVER_DISABLING    26
+#define SELECT_PLANE                27
+#define PRE_CRTC_MODE_CHANGE        28
+#define POST_CRTC_MODE_CHANGE       29
+#define VIRTUALIZE_DAC_OUT          30
+#define VIRTUALIZE_DAC_IN           31
+#define GET_CURRENT_BANK_WRITE      32
+#define GET_CURRENT_BANK_READ       33
+#define SET_BANK                    34
+#define CHECK_HIRES_MODE            35
+#define GET_TOTAL_VRAM_SIZE         36
+#define GET_BANK_SIZE               37
+#define SET_HIRES_MODE              38
+#define PRE_HIRES_SAVE_RESTORE      39
+#define POST_HIRES_SAVE_RESTORE     40
+#define VESA_SUPPORT                41
+#define GET_CHIP_ID                 42
+#define CHECK_SCREEN_SWITCH_OK      43
+#define VIRTUALIZE_BLTER_IO         44
+#define SAVE_MESSAGE_MODE_STATE     45
+#define SAVE_FORCED_PLANAR_STATE    46
+#define VESA_CALL_POST_PROCESSING   47
+#define PRE_INT_10_MODE_SET         48
+
+#define NBR_MINI_VDD_FUNCTIONS      49
+
+/* Port sizes. */
+#define BYTE_LENGTHED               1
+#define WORD_LENGTHED               2
+
+/* Flag bits. */
+#define GOING_TO_WINDOWS_MODE       1
+#define GOING_TO_VGA_MODE           2
+#define DISPLAY_DRIVER_DISABLED     4
+#define IN_WINDOWS_HIRES_MODE       8
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ddk/valmode.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,20 @@
+
+/* Return values for ValidateMode. */
+#define VALMODE_YES		    0   /* Mode is good. */
+#define VALMODE_NO_WRONGDRV 1   /* Hardware not supported by driver. */
+#define VALMODE_NO_NOMEM	2   /* Insufficient video memory. */
+#define VALMODE_NO_NODAC	3   /* DAC cannot handle bit depth. */
+#define VALMODE_NO_UNKNOWN	4   /* Some other problem. */
+
+
+/* Structure describing a display mode. */
+typedef struct {
+    UINT    dvmSize;    /* Size of this struct. */
+    UINT    dvmBpp;     /* Mode color depth. */
+    int     dvmXRes;    /* Mode X resolution. */
+    int     dvmYRes;    /* Mode Y resolution. */
+} DISPVALMODE;
+
+/* Must be exported by name from driver. Recommended ordinal is 700. */
+extern UINT WINAPI ValidateMode( DISPVALMODE FAR *lpMode );
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dibcall.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+
+/*
+ * What's this all about? Most of the required exported driver functions can
+ * be passed straight to the DIB Engine. The DIB Engine in some cases requires
+ * an additional parameter.
+ *
+ * See the dibthunk.asm module for functions that can be handled easily. Note
+ * that although the logic could be implemented in C, it can be done more
+ * efficiently in assembly. Forwarders turn into simple jumps, and functions
+ * with an extra parameter can be implemented with very small overhead, saving
+ * stack space and extra copying.
+ *
+ * This module deals with the very few functions that need additional logic but
+ * are not hardware specific.
+ */
+
+
+/* Exported as DISPLAY.104 */
+void WINAPI __loadds CheckCursor( void )
+{
+    if( wEnabled ) {
+        DIB_CheckCursorExt( lpDriverPDevice );
+    }
+}
+
+/* If there is no hardware screen-to-screen BitBlt, there's no point in
+ * this and we can just forward BitBlt to the DIB Engine.
+ */
+#ifdef HWBLT
+
+extern BOOL WINAPI (* BitBltDevProc)( LPDIBENGINE, WORD, WORD, LPPDEVICE, WORD, WORD,
+                                      WORD, WORD, DWORD, LPBRUSH, LPDRAWMODE );
+
+/* See if a hardware BitBlt can be done. */
+BOOL WINAPI BitBlt( LPDIBENGINE lpDestDev, WORD wDestX, WORD wDestY, LPPDEVICE lpSrcDev,
+                    WORD wSrcX, WORD wSrcY, WORD wXext, WORD wYext, DWORD dwRop3,
+                    LPBRUSH lpPBrush, LPDRAWMODE lpDrawMode )
+{
+    WORD    dstFlags = lpDestDev->deFlags;
+
+    /* The destination must be video memory and not busy. */
+    if( (dstFlags & VRAM) && !(dstFlags & BUSY) ) {
+        /* If palette translation is needed, only proceed if source
+         * and destination device are identical.
+         */
+        if( !(dstFlags & PALETTE_XLAT) || (lpDestDev == lpSrcDev) ) {
+            /* If there is a hardware acceleration callback, use it. */
+            if( BitBltDevProc ) {
+                return( BitBltDevProc( lpDestDev, wDestX, wDestY, lpSrcDev, wSrcX, wSrcY, wXext, wYext, dwRop3, lpPBrush, lpDrawMode ) );
+            }
+        }
+    }
+    return( DIB_BitBlt( lpDestDev, wDestX, wDestY, lpSrcDev, wSrcX, wSrcY, wXext, wYext, dwRop3, lpPBrush, lpDrawMode ) );
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dibthunk.asm	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,112 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Copyright (c) 2012-2022  Michal Necasek
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Define a macro which produces a DIB engine thunk, taking care of all
+; externs and publics.
+; The DIB_xxxExt functions take one additional parameter. To minimize
+; stack space copying and usage, the thunk pops off the return address,
+; pushes the additional parameter (always the last parameter of
+; DIB_xxxExt), pushes the return address back, and jumps to DIB_xxxExt.
+; The AX, ECX, and ES registers are modified with no ill effect since
+; they aren't used by the Pascal calling convention to pass arguments.
+
+;; Thunk macro with additional parameters.
+DIBTHK	macro	name, param
+extrn	DIB_&name&Ext : far
+public	name
+name:
+	mov	ax, DGROUP	; Load ES with our data segment.
+	mov	es, ax
+	assume	es:DGROUP
+	pop	ecx		; Save the 16:16 return address in ECX.
+	push	param		; Push the additional parameter.
+	push	ecx		; Put the return address back.
+	jmp	DIB_&name&Ext	; Off to the DIB Engine we go.
+	endm
+
+;; Simple forwarder macro.
+DIBFWD	macro	name
+extrn	DIB_&name : far
+public	name
+name:
+	jmp	DIB_&name	; Just jump to the DIB Engine.
+	endm
+
+;; Additional variables that need to be pushed are in the data segment.
+_DATA	segment public 'DATA'
+
+extrn	_lpDriverPDevice : dword
+extrn	_wPalettized : word
+
+_DATA	ends
+
+DGROUP	group 	_DATA
+
+_TEXT	segment	public 'CODE'
+
+.386
+assume	ds:nothing, es:nothing
+
+;; Thunks that push an additional parameter.
+;; Sorted by ordinal number.
+DIBTHK	EnumObj, 		_lpDriverPDevice
+DIBTHK	RealizeObject,		_lpDriverPDevice
+DIBTHK	DibBlt,			_wPalettized
+DIBTHK	GetPalette,		_lpDriverPDevice
+DIBTHK	SetPaletteTranslate,	_lpDriverPDevice
+DIBTHK	GetPaletteTranslate,	_lpDriverPDevice
+DIBTHK	UpdateColors,		_lpDriverPDevice
+DIBTHK	SetCursor,		_lpDriverPDevice
+DIBTHK	MoveCursor,		_lpDriverPDevice
+
+;; Forwarders that simply jump to the DIB Engine.
+;; Sorted by ordinal number.
+ifndef HWBLT
+DIBFWD	BitBlt
+endif
+DIBFWD	ColorInfo
+DIBFWD	Control
+DIBFWD	EnumDFonts
+DIBFWD	Output
+DIBFWD	Pixel
+DIBFWD	Strblt
+DIBFWD	ScanLR
+DIBFWD	DeviceMode
+DIBFWD	ExtTextOut
+DIBFWD	GetCharWidth
+DIBFWD	DeviceBitmap
+DIBFWD	FastBorder
+DIBFWD	SetAttribute
+DIBFWD	CreateDIBitmap
+DIBFWD	DibToDevice
+DIBFWD	StretchBlt
+DIBFWD	StretchDIBits
+DIBFWD	SelectBitmap
+DIBFWD	BitmapBits
+DIBFWD	Inquire
+
+_TEXT	ends
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/enable.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,453 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* GDI Enable (with ReEnable) and Disable implementation. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <minivdd.h>
+#include "minidrv.h"
+
+#include <string.h>
+
+/* Pretend we have a 208 by 156 mm screen. */
+#define DISPLAY_HORZ_MM     208
+#define DISPLAY_VERT_MM     156
+
+/* Size in English units. Looks pretty random. */
+#define DISPLAY_SIZE_EN     325
+/* Size in twips. Just as random. */
+#define DISPLAY_SIZE_TWP    2340
+
+LPDIBENGINE lpDriverPDevice = 0;    /* This device's PDEV that's passed to GDI. */
+WORD wEnabled = 0;                  /* Is this device enabled? */
+RGBQUAD FAR *lpColorTable = 0;      /* Current color table. */
+
+static BYTE bReEnabling = 0;        /* Set when re-enabling PDEV. */
+static WORD wDIBPdevSize = 0;
+
+
+/* 1bpp Color Table (non-palettized). */
+const DIBColorEntry DIB1ColorTable[] = {
+    /* blue  red  green flags */
+    { 0   , 0   , 0   , 0          },
+    { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+/* 4bpp Color Table (non-palettized). */
+const DIBColorEntry DIB4ColorTable[] = {
+    /* blue  red  green flags */
+    { 0   , 0   , 0   , 0          },
+    { 0   , 0   , 0x80, 0          },
+    { 0   , 0x80, 0   , 0          },
+    { 0   , 0x80, 0x80, 0          },
+    { 0x80, 0   , 0   , 0          },
+    { 0x80, 0   , 0x80, 0          },
+    { 0x80, 0x80, 0   , 0          },
+    { 0xC0, 0xC0, 0xC0, MAPTOWHITE },
+    { 0x80, 0x80, 0x80, MAPTOWHITE },
+    { 0   , 0   , 0xFF, 0          },
+    { 0   , 0xFF, 0   , MAPTOWHITE },
+    { 0   , 0xFF, 0xFF, MAPTOWHITE },
+    { 0xFF, 0   , 0   , 0          },
+    { 0xFF, 0   , 0xFF, 0          },
+    { 0xFF, 0xFF, 0   , MAPTOWHITE },
+    { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+/* 8bpp Color Table (palettized), first 10 entries. */
+const DIBColorEntry DIB8ColorTable1[] = {
+    /* blue  red  green flags */
+    { 0   , 0   , 0   , 0          },
+    { 0   , 0   , 0x80, 0          },
+    { 0   , 0x80, 0   , 0          },
+    { 0   , 0x80, 0x80, 0          },
+    { 0x80, 0   , 0   , 0          },
+    { 0x80, 0   , 0x80, 0          },
+    { 0x80, 0x80, 0   , 0          },
+    { 0xC0, 0xC0, 0xC0, MAPTOWHITE },
+    { 0xC0, 0xDC, 0xC0, MAPTOWHITE | NONSTATIC },
+    { 0xF0, 0xCA, 0xA6, MAPTOWHITE | NONSTATIC }
+};
+
+/* 8bpp Color Table (palettized), all middle entries (10-245). */
+const DIBColorEntry DIB8ColorTable2[] = {
+    /* blue  red  green flags */
+    { 0, 0, 0, NONSTATIC }
+};
+
+/* 8bpp Color Table (palettized), last 10 entries (246-255). */
+const DIBColorEntry DIB8ColorTable3[] = {
+    /* blue  red  green flags */
+    { 0xF0, 0xFB, 0xFF, MAPTOWHITE | NONSTATIC },
+    { 0xA4, 0xA0, 0xA0, MAPTOWHITE | NONSTATIC },
+    { 0x80, 0x80, 0x80, MAPTOWHITE },
+    { 0   , 0   , 0xFF, 0          },
+    { 0   , 0xFF, 0   , MAPTOWHITE },
+    { 0   , 0xFF, 0xFF, MAPTOWHITE },
+    { 0xFF, 0   , 0   , 0          },
+    { 0xFF, 0   , 0xFF, 0          },
+    { 0xFF, 0xFF, 0   , MAPTOWHITE },
+    { 0xFF, 0xFF, 0xFF, MAPTOWHITE }
+};
+
+
+/* An undocumented function called by USER to check if display driver
+ * contains a more suitable version of a resource.
+ * Exported as ordinal 450.
+ */
+DWORD WINAPI __loadds GetDriverResourceID( WORD wResID, LPSTR lpResType )
+{
+    if( wResID == OBJ_FONT ) {
+        if( wDpi != 96 ) {
+            return( 2003 ); /* If DPI is not 96, return fonts120.bin instead. */
+        }
+    }
+    return( wResID );
+}
+
+/* Some genius at Microsoft decided that CreateDIBPDevice returns the result
+ * in EAX, not DX:AX. This is not at all documented in the Win95 DDK, but it
+ * is stated clearly in U.S. Patent 6,525,743 (granted in 2003).
+ * We just create a tiny thunk to produce a sane calling convention.
+ */
+DWORD PASCAL CreateDIBPDeviceX( LPBITMAPINFO lpInfo, LPPDEVICE lpDevice, LPVOID lpBits, WORD wFlags );
+#pragma aux CreateDIBPDeviceX = \
+    "call   CreateDIBPDevice"   \
+    "mov    dx, ax"             \
+    "shr    eax, 16"            \
+    "xchg   ax, dx"
+
+#pragma code_seg( _INIT )
+
+/* GDI calls Enable twice at startup, first to query the GDIINFO structure
+ * and then to initialize the video hardware.
+ */
+UINT WINAPI __loadds Enable( LPVOID lpDevice, UINT style, LPSTR lpDeviceType,
+                             LPSTR lpOutputFile, LPVOID lpStuff )
+{
+    WORD    rc;
+    WORD    wPalCnt;
+
+    dbg_printf( "Enable: lpDevice=%WP style=%X bReEnabling=%u wPalettized=%u\n", lpDevice, style, bReEnabling, wPalettized );
+    if( !(style & 1) ) {    /* Only test the low bit! */
+        LPDIBENGINE     lpEng = lpDevice;
+        LPBITMAPINFO    lpInfo;
+        WORD            wFlags;
+        DWORD           dwRet;
+
+        /* Initialize the PDEVICE. */
+        lpDriverPDevice = lpDevice;
+        rc = PhysicalEnable();
+        if( !rc ) {
+            dbg_printf( "Enable: PhysicalEnable failed!\n" );
+            return( 0 );
+        }
+        if( !bReEnabling ) {
+            int_2Fh( STOP_IO_TRAP );
+        }
+
+        /* Pass down to the DIB engine. */
+        DIB_Enable( lpDevice, style, lpDeviceType, lpOutputFile, lpStuff );
+
+        if( wPalettized )
+            DIB_SetPaletteTranslateExt( NULL, lpDriverPDevice );
+
+        dbg_printf( "Enable: wBpp=%u wDpi=%u wScreenX=%u wScreenY=%u wDIBPdevSize=%x\n",
+                    wBpp, wDpi, wScreenX, wScreenY, wDIBPdevSize );
+
+        /* Fill out the bitmap header. */
+        /// @todo Does wDIBPdevSize have to equal sizeof(DIBENGINE)?
+        lpInfo = (LPVOID)((LPBYTE)lpDevice + wDIBPdevSize);
+        _fmemset( &lpInfo->bmiHeader, 0, sizeof( lpInfo->bmiHeader ) );
+        lpInfo->bmiHeader.biSize     = sizeof( lpInfo->bmiHeader );
+        lpInfo->bmiHeader.biWidth    = wScreenX;
+        lpInfo->bmiHeader.biHeight   = wScreenY;
+        lpInfo->bmiHeader.biPlanes   = 1;
+        lpInfo->bmiHeader.biBitCount = wBpp;
+
+        /* Set up the color table for non-direct color modes. */
+        if( wBpp <= 8 ) {
+            DIBColorEntry FAR   *lpDefaultClr;
+
+            switch( wBpp ) {
+            case 8:
+                lpDefaultClr = DIB8ColorTable1;
+                wPalCnt = sizeof( DIB8ColorTable1 );
+                break;
+            case 4:
+                lpDefaultClr = DIB4ColorTable;
+                wPalCnt = sizeof( DIB4ColorTable );
+                break;
+            case 1:
+            default:
+                lpDefaultClr = DIB1ColorTable;
+                wPalCnt = sizeof( DIB1ColorTable );
+                break;
+            }
+            lpColorTable = &lpInfo->bmiColors;
+
+            if( !bReEnabling ) {
+                _fmemcpy( lpColorTable, lpDefaultClr, wPalCnt );
+                /* For 8bpp, fix up the rest of the palette. */
+                if( wBpp == 8 ) {
+                    int     i;
+
+                    /* The entries at index 10 to 245 are all the same. */
+                    for( i = 10; i < 246; ++i )
+                        lpColorTable[i] = DIB8ColorTable2[0];
+
+                    _fmemcpy( &lpColorTable[246], DIB8ColorTable3, sizeof( DIB8ColorTable3 ) );
+                }
+            }
+        }
+
+        wFlags = wPDeviceFlags;
+        if( wPalettized )
+            wFlags |= PALETTIZED;
+
+        /* Call the DIB Engine to set up the PDevice. */
+        dbg_printf( "lpInfo=%WP lpDevice=%WP lpColorTable=%WP wFlags=%X ScreenSelector=%X\n", lpInfo, lpDevice, lpColorTable, wFlags, ScreenSelector );
+        dwRet = CreateDIBPDeviceX( lpInfo, lpDevice, ScreenSelector :> 0, wFlags );
+        if( !dwRet ) {
+            dbg_printf( "Enable: CreateDIBPDevice failed!\n" );
+            return( 0 );
+        }
+        dbg_printf( "Enable: CreateDIBPDevice returned %lX\n", dwRet );
+
+        /* Now fill out the begin/end access callbacks. */
+        lpEng->deBeginAccess = DIB_BeginAccess;
+        lpEng->deEndAccess   = DIB_EndAccess;
+
+        /* Program the DAC in non-direct color modes. */
+        if( wBpp <= 8 ) {
+            switch( wBpp ) {
+            case 8:
+                wPalCnt = 256;
+                break;
+            case 4:
+                wPalCnt = 16;
+                break;
+            case 1:
+            default:
+                wPalCnt = 2;
+                break;
+            }
+            SetRAMDAC_far( 0, wPalCnt, lpColorTable );
+        }
+
+        if( !bReEnabling ) {
+            HookInt2Fh();
+        }
+        wEnabled = 1;
+        return( 1 );
+    } else {
+        /* Fill out GDIINFO for GDI. */
+        LPGDIINFO   lpInfo = lpDevice;
+
+        /* Start with passing down to the DIB engine. It will set dpCurves through dpStyleLen. */
+        DIB_Enable( lpDevice, style, lpDeviceType, lpOutputFile, lpStuff );
+
+        /* Fill out some static data. Note that some fields are set by the DIB Engine
+         * and we don't touch them (curves, lines, polygons etc.).
+         */
+        lpInfo->dpVersion    = DRV_VERSION;
+        lpInfo->dpTechnology = DT_RASDISPLAY;
+        lpInfo->dpHorzSize   = DISPLAY_HORZ_MM;
+        lpInfo->dpVertSize   = DISPLAY_VERT_MM;
+        lpInfo->dpPlanes     = 1;
+        lpInfo->dpCapsFE     = 0;
+        lpInfo->dpNumFonts   = 0;
+
+        /* Now set the fields that depend on current mode. */
+        lpInfo->dpHorzRes = wScrX;
+        lpInfo->dpVertRes = wScrY;
+
+        lpInfo->dpMLoWin.xcoord = DISPLAY_HORZ_MM * 10;
+        lpInfo->dpMLoWin.ycoord = DISPLAY_VERT_MM * 10;
+        lpInfo->dpMLoVpt.xcoord = wScrX;
+        lpInfo->dpMLoVpt.ycoord = -wScrY;
+
+        lpInfo->dpMHiWin.xcoord = DISPLAY_HORZ_MM * 100;
+        lpInfo->dpMHiWin.ycoord = DISPLAY_VERT_MM * 100;
+        lpInfo->dpMHiVpt.xcoord = wScrX;
+        lpInfo->dpMHiVpt.ycoord = -wScrY;
+
+        /* These calculations are a wild guess and probably don't matter. */
+        lpInfo->dpELoWin.xcoord = DISPLAY_SIZE_EN;
+        lpInfo->dpELoWin.ycoord = DISPLAY_SIZE_EN;
+        lpInfo->dpELoVpt.xcoord = wScrX / 5;
+        lpInfo->dpELoVpt.ycoord = -lpInfo->dpELoVpt.xcoord;
+
+        lpInfo->dpELoWin.xcoord = DISPLAY_SIZE_EN * 5;
+        lpInfo->dpELoWin.ycoord = DISPLAY_SIZE_EN * 5;
+        lpInfo->dpEHiVpt.xcoord = wScrX / 10;
+        lpInfo->dpEHiVpt.ycoord = -lpInfo->dpEHiVpt.xcoord;
+
+        lpInfo->dpTwpWin.xcoord = DISPLAY_SIZE_TWP;
+        lpInfo->dpTwpWin.ycoord = DISPLAY_SIZE_TWP;
+        lpInfo->dpTwpVpt.xcoord = wScrX / 10;
+        lpInfo->dpTwpVpt.ycoord = -lpInfo->dpTwpVpt.xcoord;
+
+        /* Update more GDIINFO bits. */
+        lpInfo->dpLogPixelsX = wDpi;
+        lpInfo->dpLogPixelsY = wDpi;
+        lpInfo->dpBitsPixel  = wBpp;
+        lpInfo->dpDCManage   = DC_IgnoreDFNP;
+        lpInfo->dpCaps1 |= C1_BYTE_PACKED | C1_COLORCURSOR | C1_REINIT_ABLE | C1_SLOW_CARD;
+
+        /* Grab the DIB Engine PDevice size before we add to it. */
+        wDIBPdevSize = lpInfo->dpDEVICEsize;
+        dbg_printf( "Enable: wDIBPdevSize=%X wScrX=%u wScrY=%u wBpp=%u wDpi=%u wScreenX=%u wScreenY=%u\n",
+                    wDIBPdevSize, wScrX, wScrY, wBpp, wDpi, wScreenX, wScreenY );
+
+        lpInfo->dpNumBrushes = -1;  /* Too many to count, always the same.. */
+
+        if( wBpp == 8 ) {
+            if( wPalettized ) {
+                lpInfo->dpNumPens     = 16;     /* Pens realized by driver. */
+                lpInfo->dpNumColors   = 20;     /* Colors in color table. */
+                lpInfo->dpNumPalReg   = 256;
+                lpInfo->dpPalReserved = 20;
+                lpInfo->dpColorRes    = 18;
+                lpInfo->dpRaster     |= RC_DIBTODEV + RC_PALETTE + RC_SAVEBITMAP;
+            } else {
+                lpInfo->dpNumPens     = 256;    /* Pens realized by driver. */
+                lpInfo->dpNumColors   = 256;    /* Colors in color table. */
+                lpInfo->dpNumPalReg   = 0;
+                lpInfo->dpPalReserved = 0;
+                lpInfo->dpColorRes    = 0;
+                lpInfo->dpRaster     |= RC_DIBTODEV;
+            }
+            lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER ) + 256 * 4;
+        } else if( wBpp > 8 ) {
+            lpInfo->dpNumPens     = -1;     /* Pens realized by driver. */
+            lpInfo->dpNumColors   = -1;     /* Colors in color table. */
+            lpInfo->dpNumPalReg   = 0;
+            lpInfo->dpPalReserved = 0;
+            lpInfo->dpColorRes    = 0;
+            lpInfo->dpRaster     |= RC_DIBTODEV;
+            lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER );
+        } else if( wBpp < 8 ) {
+            WORD    wCount;
+
+            wCount = 1 << wBpp; /* 2 or 4 for 2 or 16 bpp. */
+            lpInfo->dpNumPens     = wCount; /* Pens realized by driver. */
+            lpInfo->dpNumColors   = wCount; /* Colors in color table. */
+            lpInfo->dpNumPalReg   = 0;
+            lpInfo->dpPalReserved = 0;
+            lpInfo->dpColorRes    = 0;
+            lpInfo->dpRaster     |= RC_DIBTODEV;
+            wCount *= 4;
+            lpInfo->dpDEVICEsize += sizeof( BITMAPINFOHEADER ) + 8 + wCount;
+        }
+        dbg_printf( "sizeof(GDIINFO)=%d (%X), dpDEVICEsize=%X\n", sizeof( GDIINFO ), sizeof( GDIINFO ), lpInfo->dpDEVICEsize );
+        return( sizeof( GDIINFO ) );
+    }
+}
+
+
+/* The ReEnable function is called to dynamically change resolution.
+ * It must query the new display mode settings and then call Enable.
+ * NB: Windows 9x will not dynamically change the color depth, only
+ * resolution. Documented in MS KB Article Q127139.
+ */
+UINT WINAPI __loadds ReEnable( LPVOID lpDevice, LPGDIINFO lpInfo )
+{
+    WORD    wLastValidBpp  = wBpp;
+    WORD    wLastValidX    = wScreenX;
+    WORD    wLastValidY    = wScreenY;
+    WORD    rc;
+
+    dbg_printf( "ReEnable: lpDevice=%WP lpInfo=%WP wScreenX=%u wScreenY=%u\n", lpDevice, lpInfo, wScreenX, wScreenY );
+
+    /* Figure out the new mode. */
+    ReadDisplayConfig();
+    dbg_printf( "ReEnable: wScreenX=%u wScreenY=%u wBpp=%u\n", wScreenX, wScreenY, wBpp );
+
+    /* Let Enable know it doesn't need to do everything. */
+    bReEnabling = 1;
+
+    /* Don't let the cursor mess with things. */
+    DIB_BeginAccess( lpDevice, 0, 0, wScreenX - 1, wScreenY - 1, CURSOREXCLUDE );
+
+    /* Create a new PDevice and set the new mode. Returns zero on failure. */
+    rc = Enable( lpDevice, 0, NULL, NULL, NULL );
+
+    /* Drawing the cursor is safe again. */
+    DIB_EndAccess( lpDevice, CURSOREXCLUDE );
+
+    if( rc ) {
+        /* Enable succeeded, fill out GDIINFO. */
+        Enable( lpInfo, 1, NULL, NULL, NULL );
+        rc = 1;
+    } else {
+        dbg_printf( "ReEnable: Enable failed!\n" );
+        /* Couldn't set new mode. Try to get the old one back. */
+        wScreenX = wLastValidX;
+        wScreenY = wLastValidY;
+        wBpp     = wLastValidBpp;
+
+        Enable( lpDevice, 0, NULL, NULL, NULL );
+
+        /* And force a repaint. */
+        RepaintFunc();
+        rc = 0;
+    }
+
+    bReEnabling = 0;
+    return( rc );
+}
+
+void int_10h( unsigned ax );
+#pragma aux int_10h =   \
+    "int    10h"        \
+    parm [ax];
+
+/* Disable graphics and go back to a text mode. */
+UINT WINAPI __loadds Disable( LPVOID lpDevice )
+{
+    LPDIBENGINE lpEng = lpDevice;
+
+    dbg_printf( "Disable: lpDevice=%WP\n", lpDevice );
+
+    /* Start disabling and mark the PDevice busy. */
+    wEnabled = 0;
+    lpEng->deFlags |= BUSY; /// @todo Does this need to be a locked op?
+
+    /* Re-enable I/O trapping before we start setting a standard VGA mode. */
+    int_2Fh( START_IO_TRAP );
+
+    /* Tell VDD we're going away. */
+    CallVDD( VDD_DRIVER_UNREGISTER );
+
+    /* Set standard 80x25 text mode using the BIOS. */
+    int_10h( 3 );
+
+    /* And unhook INT 2F. */
+    UnhookInt2Fh();
+
+    return( 1 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/init.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,172 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver module initialization. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <minivdd.h>
+#include "minidrv.h"
+
+
+/* GlobalSmartPageLock is a semi-undocumented function. Not officially
+ * documented but described in KB Article Q180586. */
+UINT WINAPI GlobalSmartPageLock( HGLOBAL hglb );
+
+WORD    wScrX       = 640;  /* Current X resolution. */
+WORD    wScrY       = 480;  /* Current Y resolution. */
+WORD    wDpi        = 96;   /* Current DPI setting. */
+WORD    wBpp        = 8;    /* Current BPP setting. */
+WORD    wPalettized = 0;    /* Non-zero if palettized. */
+
+WORD    OurVMHandle   = 0;  /* The current VM's ID. */
+DWORD   VDDEntryPoint = 0;  /* The VDD entry point. */
+
+/* On Entry:
+ * EAX    = Function code (VDD_GET_DISPLAY_CONFIG)
+ * EBX    = This VM's handle
+ * ECX    = Size of DISPLAYINFO structure
+ * EDX    = Zero to tell VDD to try virtualizing
+ * ES:EDI = Pointer to DISPLAYINFO structure to be
+ *          filled
+ *
+ * On Return:
+ * EAX    = Return code (0 = succeess, -1 = failed)
+ */
+extern DWORD CallVDDGetDispConf( WORD Function, WORD wDInfSize, LPVOID pDInf );
+#pragma aux CallVDDGetDispConf =    \
+    ".386"                          \
+    "movzx  eax, ax"                \
+    "movzx  ecx, cx"                \
+    "movzx  ebx, OurVMHandle"       \
+    "movzx  edi, di"                \
+    "call   dword ptr VDDEntryPoint"\
+    "mov    edx, eax"               \
+    "shr    edx, 16"                \
+    parm [ax] [cx] [es di];
+
+
+#pragma code_seg( _INIT )
+
+/* Read the display settings from SYSTEM.INI or Registry.
+ */
+void ReadDisplayConfig( void )
+{
+    WORD        wX, wY;
+    UINT        bIgnoreRegistry;
+    MODEDESC    mode;
+
+    /* Get the DPI, default to 96. */
+    wDpi = GetPrivateProfileInt( "display", "dpi", 96, "system.ini" );
+
+    /* Get X and Y resolution. */
+    wX = GetPrivateProfileInt( "display", "x_resolution", 0, "system.ini" );
+    wY = GetPrivateProfileInt( "display", "y_resolution", 0, "system.ini" );
+
+    /* Get the bits per pixel. */
+    wBpp = GetPrivateProfileInt( "display", "bpp", 0, "system.ini" );
+
+    dbg_printf( "SYSTEM.INI: %ux%u %ubpp %udpi\n", wX, wY, wBpp, wDpi );
+
+    bIgnoreRegistry = GetPrivateProfileInt( "display", "IgnoreRegistry", 0, "system.ini" );
+
+    if( !bIgnoreRegistry ) {
+        DISPLAYINFO DispInfo;
+        DWORD       dwRc;
+
+        dwRc = CallVDDGetDispConf( VDD_GET_DISPLAY_CONFIG, sizeof( DispInfo ), &DispInfo );
+        if( (dwRc != VDD_GET_DISPLAY_CONFIG) && !dwRc ) {
+            /* Call succeeded, use the data. */
+            wScrX = DispInfo.diXRes;
+            wScrY = DispInfo.diYRes;
+            wBpp = DispInfo.diBpp;
+
+            dbg_printf( "Registry: %ux%u %ubpp %udpi\n", DispInfo.diXRes, DispInfo.diYRes, DispInfo.diBpp, DispInfo.diDPI );
+
+            /* DPI might not be set, careful. */
+            if( DispInfo.diDPI )
+                wDpi = DispInfo.diDPI;
+        } else {
+            dbg_printf( "VDD_GET_DISPLAY_CONFIG failed, dwRc=%lX\n",dwRc );
+        }
+    }
+
+    mode.xRes = wScrX;
+    mode.yRes = wScrY;
+    mode.bpp  = wBpp;
+
+    if( !FixModeInfo( &mode ) ) {
+        /* Values were changed. */
+        wScrX = mode.xRes;
+        wScrY = mode.yRes;
+        wBpp  = mode.bpp;
+    }
+
+    /* For 8bpp, read the 'palettized' setting. Default to enabled. */
+    if( wBpp == 8 )
+        wPalettized = GetPrivateProfileInt( "display", "palettized", 1, "system.ini" );
+    else
+        wPalettized = 0;
+}
+
+#define VDD_ID      10  /* Virtual Display Driver ID. */
+
+/* Get Device API Entry Point. */
+void __far *int_2F_GetEP( unsigned ax, unsigned bx );
+#pragma aux int_2F_GetEP =  \
+    "int    2Fh"            \
+    parm [ax] [bx] value [es di];
+
+/* Get "magic number" (current Virtual Machine ID) for VDD calls. */
+WORD int_2F_GetVMID( unsigned ax );
+#pragma aux int_2F_GetVMID =    \
+    "int    2Fh"                \
+    parm [ax] value [bx];
+
+/* Dummy pointer to get at the _TEXT segment. Is there any easier way? */
+extern char __based( __segname( "_TEXT" ) ) *pText;
+
+/* This is a standard DLL entry point. Note that DS is already set
+ * to point to this DLL's data segment on entry.
+ */
+#pragma aux DriverInit parm [cx] [di] [es si]
+UINT FAR DriverInit( UINT cbHeap, UINT hModule, LPSTR lpCmdLine )
+{
+    /* Lock the code segment. */
+    GlobalSmartPageLock( (__segment)pText );
+
+    /* Query the entry point of the Virtual Display Device. */
+    VDDEntryPoint = (DWORD)int_2F_GetEP( 0x1684, VDD_ID );
+
+    /* Obtain the "magic number" needed for VDD calls. */
+    OurVMHandle = int_2F_GetVMID( 0x1683 );
+
+    dbg_printf( "DriverInit: VDDEntryPoint=%WP, OurVMHandle=%x\n", VDDEntryPoint, OurVMHandle );
+
+    /* Read the display configuration before doing anything else. */
+    ReadDisplayConfig();
+
+    return( 1 );    /* Success. */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,104 @@
+OBJS = dibthunk.obj dibcall.obj enable.obj init.obj palette.obj &
+       scrsw.obj sswhook.obj modes.obj boxv.obj
+
+INCS = -I$(%WATCOM)\h\win -Iddk
+
+# Define HWBLT if BitBlt can be accelerated.
+#FLAGS = -DHWBLT
+
+# Set DBGPRINT to add debug printf logging.
+# DBGPRINT = 1
+!ifdef DBGPRINT
+FLAGS += -DDBGPRINT
+OBJS  += dbgprint.obj
+# Need this to work with pre-made boxv9x.lnk
+DBGFILE = file dbgprint.obj
+!else
+DBGFILE =
+!endif
+
+boxvmini.drv : $(OBJS) display.res dibeng.lib boxv9x.lnk
+	wlink op quiet, start=DriverInit_ disable 2055 @boxv9x.lnk $(DBGFILE)
+	wrc -q display.res $@
+
+# Linker script
+boxv9x.lnk : boxv9x.def
+        ms2wlink $(OBJS),boxvmini.drv,boxvmini.map,dibeng.lib clibs.lib,boxv9x.def > boxv9x.lnk
+
+# Object files
+boxv.obj : boxv.c .autodepend
+	wcc -q -wx -s -zu -zls -3 $(FLAGS) $<
+
+dbgprint.obj : dbgprint.c .autodepend
+	wcc -q -wx -s -zu -zls -3 $(FLAGS) $<
+
+dibcall.obj : dibcall.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+dibthunk.obj : dibthunk.asm
+	wasm -q $(FLAGS) $<
+
+enable.obj : enable.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+init.obj : init.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+palette.obj : palette.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+sswhook.obj : sswhook.asm
+	wasm -q $(FLAGS) $<
+
+modes.obj : modes.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+scrsw.obj : scrsw.c .autodepend
+	wcc -q -wx -s -zu -zls -3 -zW $(INCS) $(FLAGS) $<
+
+# Resources
+display.res : res/display.rc res/colortab.bin res/config.bin res/fonts.bin res/fonts120.bin .autodepend
+	wrc -q -r -ad -bt=windows -fo=$@ -Ires -I$(%WATCOM)/h/win res/display.rc
+
+res/colortab.bin : res/colortab.c
+	wcc -q $(INCS) $<
+	wlink op quiet disable 1014, 1023 name $@ sys dos output raw file colortab.obj
+
+res/config.bin : res/config.c
+	wcc -q $(INCS) $<
+	wlink op quiet disable 1014, 1023 name $@ sys dos output raw file config.obj
+
+res/fonts.bin : res/fonts.c .autodepend
+	wcc -q $(INCS) $<
+	wlink op quiet disable 1014, 1023 name $@ sys dos output raw file fonts.obj
+
+res/fonts120.bin : res/fonts120.c .autodepend
+	wcc -q $(INCS) $<
+	wlink op quiet disable 1014, 1023 name $@ sys dos output raw file fonts120.obj
+
+# Libraries
+dibeng.lib : ddk/dibeng.lbc
+	wlib -b -q -n -fo -ii @$< $@
+
+# Cleanup
+clean : .symbolic
+    rm *.obj
+    rm *.err
+    rm *.lib
+    rm *.drv
+    rm *.map
+    rm *.res
+    rm *.img
+    rm res/*.obj
+    rm res/*.bin
+
+image : .symbolic boxv9x.img
+
+# Create a 1.44MB distribution floppy image.
+# NB: The mkimage tool is not supplied.
+boxv9x.img : boxvmini.drv boxv9x.inf readme.txt
+    if not exist dist mkdir dist
+    copy boxvmini.drv dist
+    copy boxv9x.inf   dist
+    copy readme.txt   dist
+    mkimage -l BOXV9X -o boxv9x.img dist
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/minidrv.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,99 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* First definitions that don't appear to be in any "official" header. */
+
+#define DRV_VERSION         0x0400      /* Windows 4.0 aka Windows 95. */
+
+/* Int 2Fh subfunctions. */
+#define STOP_IO_TRAP        0x4000      /* Stop trapping video I/O. */
+#define SCREEN_SWITCH_OUT   0x4001      /* DOS session going to background. */
+#define SCREEN_SWITCH_IN    0x4002      /* DOS session going to foreground. */
+#define ENTER_CRIT_REG      0x4003      /* Enter critical section notification. */
+#define EXIT_CRIT_REG       0x4004      /* Leave critical section notification. */
+#define START_IO_TRAP       0x4007      /* Start trapping video I/O. */
+
+/* Internal interfaces within minidriver. */
+
+/* A simple mode descriptor structure. */
+typedef struct {
+    WORD    xRes;
+    WORD    yRes;
+    WORD    bpp;
+} MODEDESC, FAR *LPMODEDESC;
+
+
+extern WORD FixModeInfo( LPMODEDESC lpMode );
+extern int PhysicalEnable( void );
+extern void FAR SetRAMDAC_far( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal );
+extern void ReadDisplayConfig( void );
+extern void FAR RestoreDesktopMode( void );
+extern FARPROC RepaintFunc;
+extern void HookInt2Fh( void );
+extern void UnhookInt2Fh( void );
+
+#ifdef DBGPRINT
+extern void dbg_printf( const char *s, ... );
+#else
+/* The "Meaningless use of an expression" warning gets too annoying. */
+#pragma disable_message( 111 );
+#define dbg_printf  1 ? (void)0 : (void)
+#endif
+
+extern LPDIBENGINE lpDriverPDevice; /* DIB Engine PDevice. */
+extern WORD ScreenSelector;         /* Selector of video memory. */
+extern WORD wPalettized;            /* Non-zero if palettized device. */
+extern WORD wPDeviceFlags;          /* Current GDI device flags. */
+extern WORD wDpi;                   /* Current DPI. */
+extern WORD wBpp;                   /* Current bits per pixel. */
+extern WORD wScrX;                  /* Configured X resolution. */
+extern WORD wScrY;                  /* Configured Y resolution. */
+extern WORD wScreenX;               /* Screen width in pixels. */
+extern WORD wScreenY;               /* Screen height in pixels. */
+extern WORD wEnabled;               /* PDevice enabled flag. */
+extern RGBQUAD FAR *lpColorTable;   /* Current color table. */
+
+extern DWORD    VDDEntryPoint;
+extern WORD     OurVMHandle;
+
+/* Inlines needed in multiple modules. */
+
+void int_2Fh( unsigned ax );
+#pragma aux int_2Fh =   \
+    "int    2Fh"        \
+    parm [ax];
+
+/* NB: It's unclear of EAX/EBX really need preserving. */
+extern void CallVDD( unsigned Function );
+#pragma aux CallVDD =               \
+    ".386"                          \
+    "push   eax"                    \
+    "push   ebx"                    \
+    "movzx  eax, ax"                \
+    "movzx  ebx, OurVMHandle"       \
+    "call dword ptr VDDEntryPoint"  \
+    "pop    ebx"                    \
+    "pop    eax"                    \
+    parm [ax];
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modes.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,427 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver mode management. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include <valmode.h>
+#include <minivdd.h>
+#include "minidrv.h"
+#include "boxv.h"
+
+
+/* Somewhat arbitrary max resolution. */
+#define RES_MAX_X   (5 * 1024)
+#define RES_MAX_Y   (5 * 768)
+
+
+/* Generic DPMI calls, only used in this module. */
+extern WORD DPMI_AllocLDTDesc( WORD cSelectors );
+#pragma aux DPMI_AllocLDTDesc = \
+    "xor    ax, ax"             \
+    "int    31h"                \
+    "jnc    OK"                 \
+    "xor    ax, ax"             \
+    "OK:"                       \
+    parm [cx];
+
+extern DWORD DPMI_GetSegBase( WORD Selector );
+#pragma aux DPMI_GetSegBase =   \
+    "mov    ax, 6"              \
+    "int    31h"                \
+    "mov    ax, cx"             \
+    "xchg   ax, dx"             \
+    parm [bx] modify [cx];
+
+extern void DPMI_SetSegBase( WORD Selector, DWORD Base );
+#pragma aux DPMI_SetSegBase =   \
+    "mov    ax, 7"              \
+    "int    31h"                \
+    parm [bx] [cx dx];
+
+extern void DPMI_SetSegLimit( WORD Selector, DWORD Limit );
+#pragma aux DPMI_SetSegLimit =   \
+    "mov    ax, 8"              \
+    "int    31h"                \
+    parm [bx] [cx dx];
+
+/* NB: Compiler insists on CX:BX and DI:SI, DPMI needs it word swapped. */
+extern DWORD DPMI_MapPhys( DWORD Base, DWORD Size );
+#pragma aux DPMI_MapPhys =      \
+    "xchg   cx, bx"             \
+    "xchg   si, di"             \
+    "mov    ax, 800h"           \
+    "int    31h"                \
+    "jnc    OK"                 \
+    "xor    bx, bx"             \
+    "xor    cx, cx"             \
+    "OK:"                       \
+    "mov    dx, bx"             \
+    "mov    ax, cx"             \
+    parm [cx bx] [di si];
+
+
+WORD wScreenX       = 0;
+WORD wScreenY       = 0;
+WORD BitBltDevProc  = 0;
+WORD ScreenSelector = 0;
+WORD wPDeviceFlags  = 0;
+
+static DWORD    dwScreenFlatAddr = 0;   /* 32-bit flat address of VRAM. */
+static DWORD    dwVideoMemorySize = 0;  /* Installed VRAM in bytes. */
+static WORD     wScreenPitchBytes = 0;  /* Current scanline pitch. */
+static DWORD    dwPhysVRAM = 0;         /* Physical LFB base address. */
+
+/* These are currently calculated not needed in the absence of
+ * offscreen video memory.
+ */
+static WORD wMaxWidth  = 0;
+static WORD wMaxHeight = 0;
+
+/* On Entry:
+ * EAX   = Function code (VDD_DRIVER_REGISTER)
+ * EBX   = This VM's handle
+ * ECX   = Size of all visible scanlines in bytes
+ * EDX   = Zero to tell VDD to try virtualizing
+ * ES:DI = Pointer to function called when switching
+ *         back from fullscreen.
+ *
+ * On Return:
+ * EAX   = Amount of video memory used by VDD in bytes,
+ *         or function code if VDD call failed.
+ */
+extern DWORD CallVDDRegister( WORD Function, WORD wPitch, WORD wHeight, void _far *fRHR );
+#pragma aux CallVDDRegister =       \
+    ".386"                          \
+    "movzx  eax, ax"                \
+    "movzx  edx, dx"                \
+    "mul    edx"                    \
+    "mov    ecx, eax"               \
+    "movzx  eax, bx"                \
+    "movzx  ebx, OurVMHandle"       \
+    "xor    edx, edx"               \
+    "call   dword ptr VDDEntryPoint"\
+    "mov    edx, eax"               \
+    "shr    edx, 16"                \
+    parm [bx] [ax] [dx] [es di];
+
+
+#pragma code_seg( _INIT );
+
+/* Take a mode descriptor and change it to be a valid
+ * mode if it isn't already. Return zero if mode needed
+ * fixing (wasn't valid).
+ */
+WORD FixModeInfo( LPMODEDESC lpMode )
+{
+    WORD    rc = 1; /* Assume valid mode. */
+
+    /* First validate bits per pixel. */
+    switch( lpMode->bpp ) {
+    case 8:
+    case 16:
+    case 24:
+    case 32:
+        break;
+    default:
+        lpMode->bpp = 8;    /* Default to 8 bpp. */
+        rc = 0;             /* Mode wasn't valid. */
+    }
+
+    /* Validate mode. If resolution is under 640x480 in
+     * either direction, force 640x480.
+     */
+    if( lpMode->xRes < 640 || lpMode->yRes < 480 )
+    {
+        lpMode->xRes = 640; /* Force 640x480. */
+        lpMode->yRes = 480;
+        rc = 0;             /* Mode wasn't valid. */
+    }
+
+    /* Clip the resolution to something that probably won't make
+     * Windows have a cow.
+     */
+    if( lpMode->xRes > RES_MAX_X ) {
+        lpMode->xRes = RES_MAX_X;
+        rc = 0;
+    }
+    if( lpMode->yRes > RES_MAX_Y ) {
+        lpMode->yRes = RES_MAX_Y;
+        rc = 0;
+    }
+
+    return( rc );
+}
+
+
+/* Calculate pitch for a given horizontal resolution and bpp. */
+WORD CalcPitch( WORD x, WORD bpp )
+{
+    WORD    wPitch;
+
+    /* Valid BPP must be a multiple of 8 so it's simple. */
+    wPitch = x * (bpp / 8);
+
+    /* Align to 32 bits. */
+    wPitch = (wPitch + 3) & ~3;
+
+    return( wPitch );
+}
+
+
+/* Return non-zero if given mode is supported. */
+static int IsModeOK( WORD wXRes, WORD wYRes, WORD wBpp )
+{
+    MODEDESC    mode;
+    DWORD       dwModeMem;
+
+    mode.bpp  = wBpp;
+    mode.xRes = wXRes;
+    mode.yRes = wYRes;
+
+    /* If mode needed fixing, it's not valid. */
+    if( !FixModeInfo( &mode ) )
+        return( 0 );
+
+    /* Make sure there's enough VRAM for it. */
+    dwModeMem = (DWORD)CalcPitch( wXRes, wBpp ) * wYRes;
+    if( dwModeMem > dwVideoMemorySize )
+        return( 0 );
+
+    return( 1 );
+}
+
+
+/* Clear the visible screen by setting it to all black (zeros).
+ * NB: Assumes there is no off-screen region to the right of
+ * the visible area.
+ */
+static void ClearVisibleScreen( void )
+{
+    LPDWORD     lpScr;
+    WORD        wLines = wScreenY;
+    WORD        i;
+
+    lpScr = ScreenSelector :> 0;
+
+    while( wLines-- ) {
+        for( i = 0; i < wScreenPitchBytes / 4; ++i )
+            lpScr[i] = 0;
+        lpScr += wScreenPitchBytes; /* Scanline pitch. */
+    }
+}
+
+
+static DWORD AllocLinearSelector( DWORD dwPhysAddr, DWORD dwSize )
+{
+    WORD    wSel;
+    DWORD   dwLinear;
+
+    wSel = DPMI_AllocLDTDesc( 1 );  /* One descriptor, please. */
+    if( !wSel )
+        return( 0 );
+
+    /* Map the framebuffer physical memory. */
+    dwLinear = DPMI_MapPhys( dwPhysAddr, dwSize );
+
+    /* Now set the allocated selector to point to VRAM. */
+    DPMI_SetSegBase( wSel, dwLinear );
+    DPMI_SetSegLimit( wSel, dwSize - 1 );
+
+    return( wSel );
+}
+
+
+/* Set the currently configured mode (wXRes/wYRes) in hardware.
+ * If bFullSet is non-zero, then also reinitialize globals.
+ * When re-establishing a previously set mode (e.g. coming
+ * back from fullscreen), bFullSet will be zero.
+ * NB: BPP won't change at runtime.
+ */
+static int SetDisplayMode( WORD wXRes, WORD wYRes, int bFullSet )
+{
+    dbg_printf( "SetDisplayMode: wXRes=%u wYRes=%u\n", wXRes, wYRes );
+
+    /* Inform the VDD that the mode is about to change. */
+    CallVDD( VDD_PRE_MODE_CHANGE );
+
+    BOXV_ext_mode_set( 0, wXRes, wYRes, wBpp, wXRes, wYRes );
+
+    if( bFullSet ) {
+        wScreenX = wXRes;
+        wScreenY = wYRes;
+
+        wScreenPitchBytes = CalcPitch( wXRes, wBpp );
+        BitBltDevProc     = NULL;       /* No acceleration implemented. */
+        wPDeviceFlags     = MINIDRIVER | VRAM;
+        if( wBpp == 16 ) {
+            wPDeviceFlags |= FIVE6FIVE; /* Needed for 16bpp modes. */
+        }
+
+        wMaxWidth  = wScreenPitchBytes / (wBpp / 8);    /* We know bpp is a multiple of 8. */
+        wMaxHeight = dwVideoMemorySize / wScreenPitchBytes;
+
+        /* Offscreen regions could be calculated here. We do not use those. */
+    }
+    return( 1 );
+}
+
+
+/* Forward declaration. */
+void __far RestoreDesktopMode( void );
+
+int PhysicalEnable( void )
+{
+    DWORD   dwRegRet;
+
+    if( !ScreenSelector ) {
+        int     iChipID;
+
+        /* Extra work if driver hasn't yet been initialized. */
+        iChipID = BOXV_detect( 0, &dwVideoMemorySize );
+        if( !iChipID ) {
+            return( 0 );
+        }
+        dwPhysVRAM = BOXV_get_lfb_base( 0 );
+        dbg_printf( "PhysicalEnable: Hardware detected, dwVideoMemorySize=%lX dwPhysVRAM=%lX\n", dwVideoMemorySize, dwPhysVRAM );
+    }
+
+    if( !IsModeOK( wScrX, wScrY, wBpp ) ) {
+        /* Can't find mode, oopsie. */
+        dbg_printf( "PhysicalEnable: Mode not valid! wScrX=%u wScrY=%u wBpp=%u\n", wScrX, wScrY, wBpp );
+        return( 0 );
+    }
+
+    if( !SetDisplayMode( wScrX, wScrY, 1 ) ) {
+        /* This is not good. */
+        dbg_printf( "PhysicalEnable: SetDisplayMode failed! wScrX=%u wScrY=%u wBpp=%u\n", wScrX, wScrY, wBpp );
+        return( 0 );
+    }
+
+    /* Allocate an LDT selector for the screen. */
+    if( !ScreenSelector ) {
+        ScreenSelector = AllocLinearSelector( dwPhysVRAM, dwVideoMemorySize );
+        if( !ScreenSelector ) {
+            dbg_printf( "PhysicalEnable: AllocScreenSelector failed!\n" );
+            return( 0 );
+        }
+    }
+
+    /* NB: Currently not used. DirectDraw would need the segment base. */
+    dwScreenFlatAddr = DPMI_GetSegBase( ScreenSelector );   /* Not expected to fail. */
+
+    dbg_printf( "PhysicalEnable: RestoreDesktopMode is at %WP\n", RestoreDesktopMode );
+    dwRegRet = CallVDDRegister( VDD_DRIVER_REGISTER, wScreenPitchBytes, wScreenY, RestoreDesktopMode );
+    if( dwRegRet != VDD_DRIVER_REGISTER ) {
+        /* NB: It's not fatal if CallVDDRegister() fails. */
+        /// @todo What can we do with the returned value?
+    }
+
+    /* Let the VDD know that the mode changed. */
+    CallVDD( VDD_POST_MODE_CHANGE );
+    CallVDD( VDD_SAVE_DRIVER_STATE );
+
+    ClearVisibleScreen();
+
+    return( 1 );    /* All good. */
+}
+
+
+/* Check if the requested mode can be set. Return yes, no (with a reason),
+ * or maybe.                                                           .
+ * Must be exported by name, recommended ordinal 700.
+ * NB: Can be called when the driver is not the current display driver.
+ */
+#pragma aux ValidateMode loadds;    /* __loadds not operational due to prototype in valmode.h */
+UINT WINAPI __loadds ValidateMode( DISPVALMODE FAR *lpValMode )
+{
+    UINT        rc = VALMODE_YES;
+
+    dbg_printf( "ValidateMode: X=%u Y=%u bpp=%u\n", lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp );
+    do {
+        if( !ScreenSelector ) {
+            int     iChipID;
+
+            /* Additional checks if driver isn't running. */
+            iChipID = BOXV_detect( 0, &dwVideoMemorySize );
+            if( !iChipID ) {
+                rc = VALMODE_NO_WRONGDRV;
+                break;
+            }
+            dwPhysVRAM = BOXV_get_lfb_base( 0 );
+            dbg_printf( "ValidateMode: Hardware detected, dwVideoMemorySize=%lX dwPhysVRAM=%lX\n", dwVideoMemorySize, dwPhysVRAM );
+        }
+
+        if( !IsModeOK( lpValMode->dvmXRes, lpValMode->dvmYRes, lpValMode->dvmBpp ) ) {
+            rc = VALMODE_NO_NOMEM;
+        }
+    } while( 0 );
+
+    dbg_printf( "ValidateMode: rc=%u\n", rc );
+    return( rc );
+}
+
+#pragma code_seg( _TEXT );
+
+/* Called by the VDD in order to restore the video state when switching back
+ * to the system VM. Function is in locked memory (_TEXT segment).
+ * NB: Must reload DS, but apparently need not save/restore DS.
+ */
+#pragma aux RestoreDesktopMode loadds;
+void __far RestoreDesktopMode( void )
+{
+    dbg_printf( "RestoreDesktopMode: %ux%u, wBpp=%u\n", wScreenX, wScreenY, wBpp );
+
+    /* Set the current desktop mode again. */
+    SetDisplayMode( wScreenX, wScreenY, 0 );
+
+    /* Reprogram the DAC if relevant. */
+    if( wBpp <= 8 ) {
+        UINT    wPalCnt;
+
+        switch( wBpp ) {
+        case 8:
+            wPalCnt = 256;
+            break;
+        case 4:
+            wPalCnt = 16;
+            break;
+        default:
+            wPalCnt = 2;
+            break;
+        }
+        SetRAMDAC_far( 0, wPalCnt, lpColorTable );
+    }
+
+    /* Clear the busy flag. Quite important. */
+    lpDriverPDevice->deFlags &= ~BUSY;
+
+    /* Poke the VDD now that everything is restored. */
+    CallVDD( VDD_SAVE_DRIVER_STATE );
+
+    ClearVisibleScreen();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/palette.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,65 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Display driver palette (RAMDAC) functions. */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+#include <conio.h>      /* For port I/O prototypes. */
+#include "boxvint.h"    /* For VGA register definitions. */
+
+
+/* Load the VGA DAC with values from color table. */
+static void SetRAMDAC( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal )
+{
+    BYTE    bIndex = bStart;
+
+    /* The data format is too weird for BOXV_dac_set(). Do it by hand. */
+    outp( VGA_DAC_W_INDEX, bIndex );    /* Set starting index. */
+    while( bCount-- ) {
+        outp( VGA_DAC_DATA, lpPal[bIndex].rgbRed );
+        outp( VGA_DAC_DATA, lpPal[bIndex].rgbGreen );
+        outp( VGA_DAC_DATA, lpPal[bIndex].rgbBlue );
+        ++bIndex;
+    }
+}
+
+/* Allow calls from the _INIT segment. */
+void __far SetRAMDAC_far( UINT bStart, UINT bCount, RGBQUAD FAR *lpPal )
+{
+    SetRAMDAC( bStart, bCount, lpPal );
+}
+
+UINT WINAPI __loadds SetPalette( UINT wStartIndex, UINT wNumEntries, LPVOID lpPalette )
+{
+    /* Let the DIB engine do what it can. */
+    DIB_SetPaletteExt( wStartIndex, wNumEntries, lpPalette, lpDriverPDevice );
+
+    if( !(lpDriverPDevice->deFlags & BUSY) )
+        SetRAMDAC( wStartIndex, wNumEntries, lpColorTable );
+
+    return( 0 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readdev.txt	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,89 @@
+ Development Notes
+ =================
+
+ This Windows 9x display minidriver is almost entirely written in C. It is
+a 16-bit DLL running with SS != DS. The compiler switches were carefully
+chosen.
+
+ The driver is compiled as small model code and although it uses some C
+library functions (e.g. _fmemcpy(), _fmemset()), it does not use the C runtime
+startup code at all.
+
+ An interrupt 2Fh handler is written in assembler, and so are forwarders and
+thunks directing exported functions to the DIB Engine. The latter could be
+written in C, but assembly is significantly more efficient and not at all
+complex.
+
+ The driver is by necessity similar to Windows 95/98 DDK sample code, except
+it's written almost completely in C whereas the DDK sample drivers are written
+100% in assembly, in the tradition of Windows 3.x and 2.x display drivers.
+
+ Although the driver is a 16-bit DLL, it can freely use 386 instructions,
+since it requires a 386 or later CPU by virtue of running on Windows 95 or
+later. The driver also can and does use 32-bit registers in some situations.
+
+ The ddk subdirectory contains files which are directly derived from the
+Win9x DDK. The DDK is not used or required to build this driver, although DDK
+documentation is very useful in understanding the code. Note that the Windows
+9x DDK documentation may not cover topics documented in the Windows 3.x DDKs.
+
+ The original DDK drivers are split into two code segments, _TEXT and _INIT.
+This driver also uses those segments, but they are combined into a single
+physical segment by the linker. This simplifies the code (e.g. no problem with
+near calls into the C runtime) and given the small size of the driver, likely
+is not at all disadvantageous overall.
+
+ Note that the driver written in C is actually smaller (about 7KB vs. 8KB)
+than the assembler-only DDK sample. The C code is smarter and does not waste
+space on tables full of zeros and such, enabling it to be overall smaller even
+with the overhead of a higher level language.
+
+
+ Debug Logging
+ -------------
+
+ When built with DBGPRINT (e.g. wmake clean && wmake DBGPRINT=1), the driver
+includes debug logging implemented as dbg_printf() function. This is a small
+printf() subset with output directed to the VirtualBox debug port, such that
+the output appears in the VBox.log file.
+
+ It would be much nicer to use the C runtime printf(), but that is not at all
+possible because the small model library printf() cannot operate with SS != DS
+and is thus unusable, even if all other, less showstopping problems were
+overcome.
+
+ See driver code for dbg_printf() usage examples.
+
+
+ Building with Open Watcom 1.9
+ -----------------------------
+
+ The driver source was slightly adapted so that it builds with the released
+Open Watcom C/C++ 1.9 compiler.
+
+ The only real issue is that the ms2wlink utility shipped with Open Watcom
+version 1.9 cannot correctly process boxv9x.def, and therefore a working
+boxv9x.lnk file is supplied.
+
+ The build process was only tested on Windows 10 hosts. It should work,
+possibly with minor adaptations, on other platforms as well. That includes
+Windows 9x hosts.
+
+ The step of building a floppy image is optional and requires the mkimage
+utility (part of the OS/2 Museum's fdimg project) which is not included.
+
+
+ Replacing Active Driver
+ -----------------------
+
+ Once the boxvmini.drv driver is installed, it cannot be replaced while
+Windows 9x is running because the file is locked. It can be replaced in safe
+mode or command line boot (F8 key early in Win9x startup).
+
+ It can also be replaced by shutting down Windows 9x (not Windows Me) to
+MS-DOS compatibility mode, copying over boxvmini.drv to the WINDOWS\SYSTEM
+directory, and exiting back to Windows.
+
+ It is always possible to use the driver update dialog to install a rebuilt
+driver, but that requires more clicking and Windows must be restarted
+anyway.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.txt	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,13 @@
+This is a display minidriver for the Windows 9x family of operating systems,
+designed to run on the virtual hardware provided by VirtualBox.
+
+The driver can be installed through the Display Settings dialog or through
+the Device Manager.
+
+Supported color depths are 8/16/24/32 bits per pixel. The driver supports
+many common resolutions, limited by the available video memory (VRAM).
+
+The driver does not have a built in list of modes. It will set more or less
+any resolution between 640x480 and 5120x3840. The INF file determines the
+set of predefined modes. By editing the INF file or the resolution information
+copied into the Registry, users can add or remove available modes.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/colortab.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,62 @@
+#include "winhack.h"
+#include <gdidefs.h>
+
+/* Color table for the Control Panel. */
+
+typedef struct {
+    WORD        wCount;
+    RGBQUAD     rgbColors[];
+} COLORTABLE;
+
+COLORTABLE  ColorTbl = {
+    48,                     /* Number of entries in table. */
+    0xFF, 0x80, 0x80, 0,
+    0xFF, 0xFF, 0xE8, 0,
+    0x80, 0xFF, 0x80, 0,
+    0x00, 0xFF, 0x80, 0,
+    0x80, 0xFF, 0xFF, 0,
+    0x00, 0x80, 0xFF, 0,
+    0xFF, 0x80, 0xC0, 0,
+    0xFF, 0x80, 0xFF, 0,
+    0xFF, 0x00, 0x00, 0,
+    0xFF, 0xFF, 0x80, 0,
+    0x80, 0xFF, 0x00, 0,
+    0x00, 0xFF, 0x40, 0,
+    0x00, 0xFF, 0xFF, 0,
+    0x00, 0x80, 0xC0, 0,
+    0x80, 0x80, 0xC0, 0,
+    0xFF, 0x00, 0xFF, 0,
+    0x80, 0x40, 0x40, 0,
+    0xFF, 0xFF, 0x00, 0,
+    0x00, 0xFF, 0x00, 0,
+    0x00, 0x80, 0x80, 0,
+    0x00, 0x40, 0x80, 0,
+    0x80, 0x80, 0xFF, 0,
+    0x80, 0x00, 0x40, 0,
+    0xFF, 0x00, 0x80, 0,
+    0x80, 0x00, 0x00, 0,
+    0xFF, 0x80, 0x00, 0,
+    0x00, 0x80, 0x00, 0,
+    0x00, 0x80, 0x40, 0,
+    0x00, 0x00, 0xFF, 0,
+    0x00, 0x00, 0xA0, 0,
+    0x80, 0x00, 0x80, 0,
+    0x80, 0x00, 0xFF, 0,
+    0x40, 0x00, 0x00, 0,
+    0x80, 0x40, 0x00, 0,
+    0x00, 0x40, 0x00, 0,
+    0x00, 0x40, 0x40, 0,
+    0x00, 0x00, 0x80, 0,
+    0x00, 0x00, 0x40, 0,
+    0x40, 0x00, 0x40, 0,
+    0x40, 0x00, 0x80, 0,
+    0x00, 0x00, 0x00, 0,
+    0x80, 0x80, 0x00, 0,
+    0x80, 0x80, 0x40, 0,
+    0x80, 0x80, 0x80, 0,
+    0x40, 0x80, 0x80, 0,
+    0xC0, 0xC0, 0xC0, 0,
+    0x82, 0x82, 0x82, 0,
+    0xFF, 0xFF, 0xFF, 0
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/config.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,74 @@
+#include "winhack.h"
+#include <gdidefs.h>
+
+/* Typedef from Windows 3.1 DDK. */
+
+typedef struct {
+
+    /* machine-dependent parameters */
+    short   VertThumHeight; /* vertical thumb height (in pixels)  */
+    short   HorizThumWidth; /* horizontal thumb width (in pixels) */
+    short   IconXRatio;     /* icon width (in pixels)             */
+    short   IconYRatio;     /* icon height (in pixels)            */
+    short   CurXRatio;      /* cursor width (in pixels)           */
+    short   CurYRatio;      /* cursor height (in pixels)          */
+    short   Reserved;       /* reserved                           */
+    short   XBorder;        /* vertical-line width                */
+    short   YBorder;        /* horizontal-line width              */
+
+    /* default-system color values */
+    RGBQUAD clrScrollbar;
+    RGBQUAD clrDesktop;
+    RGBQUAD clrActiveCaption;
+    RGBQUAD clrInactiveCaption;
+    RGBQUAD clrMenu;
+    RGBQUAD clrWindow;
+    RGBQUAD clrWindowFrame;
+    RGBQUAD clrMenuText;
+    RGBQUAD clrWindowText;
+    RGBQUAD clrCaptionText;
+    RGBQUAD clrActiveBorder;
+    RGBQUAD clrInactiveBorder;
+    RGBQUAD clrAppWorkspace;
+    RGBQUAD clrHiliteBk;
+    RGBQUAD clrHiliteText;
+    RGBQUAD clrBtnFace;
+    RGBQUAD clrBtnShadow;
+    RGBQUAD clrGrayText;
+    RGBQUAD clrBtnText;
+    RGBQUAD clrInactiveCaptionText;
+} CONFIG_BIN;
+
+
+CONFIG_BIN Config = {
+    17,
+    17,
+    2,
+    2,
+    1,
+    1,
+    0,
+    1,
+    1,
+
+    192, 192, 192, 0,
+    192, 192, 192, 0,
+    000, 000, 128, 0,
+    255, 255, 255, 0,
+    255, 255, 255, 0,
+    255, 255, 255, 0,
+    000, 000, 000, 0,
+    000, 000, 000, 0,
+    000, 000, 000, 0,
+    255, 255, 255, 0,
+    192, 192, 192, 0,
+    192, 192, 192, 0,
+    255, 255, 255, 0,
+    000, 000, 128, 0,
+    255, 255, 255, 0,
+    192, 192, 192, 0,
+    128, 128, 128, 0,
+    192, 192, 192, 0,
+    000, 000, 000, 0,
+    000, 000, 000, 0
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/display.rc	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,16 @@
+/*
+ * Windows 9x minidriver resource file.
+ * Most of the contents is defined by backward compatibility
+ * requirements. Much of the detail is explained in the Windows 3.x
+ * and 2.x DDKs.
+ */
+
+#include "windows.h"
+#include "display.rcv"
+
+1          oembin  PRELOAD         config.bin
+2          oembin                  colortab.bin
+3          oembin  PRELOAD         fonts.bin
+fonts      oembin                  fonts.bin
+
+2003       oembin  PRELOAD         fonts120.bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/display.rcv	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,81 @@
+#include <ver.h>
+
+/* Macros for use in the version resource. */
+
+#define VER_FILETYPE               VFT_DRV
+#define VER_FILESUBTYPE            VFT2_DRV_DISPLAY
+#define VER_FILEDESCRIPTION_STR    "Windows 9x Display Minidriver"
+#define VER_INTERNALNAME_STR       "DISPLAY"
+#define VER_LEGALCOPYRIGHT_YEARS   "2012-2022"
+#define VER_ORIGINALFILENAME_STR   "boxvmini.drv"
+#define VER_LEGALCOPYRIGHT_STR     "Copyright \251 The OS/2 Museum " VER_LEGALCOPYRIGHT_YEARS
+#define VER_COMPANYNAME_STR        "OS/2 Museum\0"
+
+#define VER_PRODUCTNAME_STR         "Windows 9x Display Driver\0"
+#define VER_PRODUCTVERSION          2,00,0,1
+#define VER_PRODUCTVERSION_STR      "2.00.1\0"
+
+#define VER_FILEFLAGSMASK           VS_FFI_FILEFLAGSMASK
+
+#ifdef DEBUG
+#define VER_FILEFLAGS               VS_FF_DEBUG
+#else
+#define VER_FILEFLAGS               0
+#endif
+
+#define VER_FILEOS                  VOS_DOS_WINDOWS16
+
+#ifndef VER_FILEVERSION
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#endif
+
+#ifndef VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#endif
+
+/* Actual version resource structure. */
+
+VS_VERSION_INFO    VERSIONINFO
+FILEVERSION        VER_FILEVERSION
+PRODUCTVERSION     VER_PRODUCTVERSION
+FILEFLAGSMASK      VER_FILEFLAGSMASK
+FILEFLAGS          VER_FILEFLAGS
+FILEOS             VER_FILEOS
+FILETYPE           VER_FILETYPE
+FILESUBTYPE        VER_FILESUBTYPE
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904E4"
+        BEGIN
+            VALUE "CompanyName"     , VER_COMPANYNAME_STR
+            VALUE "FileDescription" , VER_FILEDESCRIPTION_STR
+            VALUE "FileVersion"     , VER_FILEVERSION_STR
+            VALUE "InternalName"    , VER_INTERNALNAME_STR
+            VALUE "LegalCopyright"  , VER_LEGALCOPYRIGHT_STR
+            VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+            VALUE "ProductName"     , VER_PRODUCTNAME_STR
+            VALUE "ProductVersion"  , VER_PRODUCTVERSION_STR
+        END
+
+#ifdef INTL
+        BLOCK "040904E4"
+        BEGIN
+            VALUE "CompanyName"     , VER_COMPANYNAME_STR
+            VALUE "FileDescription" , VER_FILEDESCRIPTION_STR
+            VALUE "FileVersion"     , VER_FILEVERSION_STR
+            VALUE "InternalName"    , VER_INTERNALNAME_STR
+            VALUE "LegalCopyright"  , VER_LEGALCOPYRIGHT_STR
+            VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+            VALUE "ProductName"     , VER_PRODUCTNAME_STR
+            VALUE "ProductVersion"  , VER_PRODUCTVERSION_STR
+        END
+#endif
+    END
+
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0409, 0x04E4    /* Needs updating. */
+    END
+END
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/fonts.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,6 @@
+/* Standard font resource for 96 DPI. */
+
+#define OEM_FNT_HEIGHT   12
+#define OEM_FNT_WIDTH    8
+
+#include "fonttmpl.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/fonts120.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,6 @@
+/* Font resource for 120 DPI. */
+
+#define OEM_FNT_HEIGHT   10
+#define OEM_FNT_WIDTH    20
+
+#include "fonttmpl.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/fonttmpl.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,55 @@
+#include "winhack.h"
+/* Trick to get a variable-size LOGFONT structure. */
+#define LF_FACESIZE
+#include <gdidefs.h>
+
+LOGFONT OEMFixed = {
+    OEM_FNT_HEIGHT,
+    OEM_FNT_WIDTH,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    255,        /* Charset. */
+    0,
+    2,          /* Clip precision. */
+    2,          /* Quality. */
+    1,          /* Pitch. */
+    "Terminal"  /* Font face. */
+};
+
+LOGFONT ANSIFixed = {
+    12,         /* Width. */
+    9,          /* Height. */
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,          /* Charset. */
+    0,
+    2,          /* Clip precision. */
+    2,          /* Quality. */
+    1,          /* Pitch. */
+    "Courier"   /* Font face. */
+};
+
+LOGFONT ANSIVar = {
+    12,         /* Width. */
+    9,          /* Height. */
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,          /* Charset. */
+    0,
+    2,          /* Clip precision. */
+    2,          /* Quality. */
+    2,          /* Pitch. */
+    "Helv"      /* Font face. */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scrsw.c	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,205 @@
+/*****************************************************************************
+
+Copyright (c) 2012-2022  Michal Necasek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*****************************************************************************/
+
+/* Screen switching support (C code). */
+
+#include "winhack.h"
+#include <gdidefs.h>
+#include <dibeng.h>
+#include "minidrv.h"
+
+/* SwitchFlags bits. */
+#define PREVENT_SWITCH  0x80    /* Don't allow screen switching. */
+#define INT_2F_HOOKED   0x01    /* INT 2Fh is hooked. */
+
+/* Accessed from sswhook.asm. */
+BYTE SwitchFlags = 0;           /* Screen switch flags, see above. */
+
+static BOOL bNoRepaint = 0;     /* Set when USER disables repaints. */
+static BOOL bPaintPending = 0;  /* Set when repaint was postponed.*/
+
+FARPROC RepaintFunc = 0;        /* Address of repaint callback. */
+
+/* Screen switch hook for INT 2Fh. */
+extern void __far SWHook( void );
+
+
+/* Repaint screen or postpone for later.
+ * Internal near call.
+ */
+void RepaintScreen( void )
+{
+    dbg_printf( "RepaintScreen: RepaintFunc=%WP, bNoRepaint=%u\n", RepaintFunc, bNoRepaint );
+    /* Do we have a repaint callback? */
+    if( RepaintFunc ) {
+        /* Either do the work or set the pending flag. */
+        if( !bNoRepaint )
+            RepaintFunc();
+        else
+            bPaintPending = TRUE;
+    }
+}
+
+/* This function is exported as DISPLAY.500 and called by USER
+ * to inform the driver that screen repaint requests should not
+ * be sent. When we need to repaint while repaints are disabled,
+ * we set an internal flag and do the redraw as soon as repaints
+ * are enabled again.
+ */
+VOID WINAPI __loadds UserRepaintDisable( BOOL bDisable )
+{
+    bNoRepaint = bDisable;
+    if( !bDisable && bPaintPending ) {
+        RepaintScreen();
+        bPaintPending = 0;
+    }
+}
+
+/* Called from INT 2Fh hook when the device is switching to the
+ * background and needs to disable drawing.
+ * Internal near call.
+ */
+void SwitchToBgnd( void )
+{
+    dbg_printf( "SwitchToBgnd\n" );
+
+    lpDriverPDevice->deFlags |= BUSY;   /// @todo Does this need to be a locked op?
+}
+
+/* Called from INT 2Fh hook when the device is switching to the
+ * foreground and needs re-enable drawing, repaiting the screen
+ * and possibly restoring the display mode.
+ * Internal near call.
+ */
+void SwitchToFgnd( void )
+{
+    dbg_printf( "SwitchToFgnd\n" );
+
+    /* If the PDevice is busy, we need to reset the display mode. */
+    if( lpDriverPDevice->deFlags & BUSY )
+        RestoreDesktopMode(); /* Will clear the BUSY flag. */
+    RepaintScreen();
+}
+
+/* This minidriver does not currently disable or enable switching.
+ * Should the functions be needed, they can be enabled.
+ */
+#if 0
+
+/* Called to prevent screen switching.
+ * Internal near call.
+ */
+void ScrSwDisable( void )
+{
+    int_2Fh( ENTER_CRIT_REG );
+    SwitchFlags |= PREVENT_SWITCH;
+}
+
+/* Called to re-enable screen switching again.
+ * Internal near call.
+ */
+void ScrSwEnable( void )
+{
+    int_2Fh( EXIT_CRIT_REG );
+    SwitchFlags &= ~PREVENT_SWITCH;
+}
+
+#endif
+
+#pragma code_seg( _INIT )
+
+/* The pointer is in the code (_TEXT) segment, not data segment.
+ * Defined in sswhook.asm.
+ */
+extern void __far * __based( __segname( "_TEXT" ) ) OldInt2Fh;
+
+
+/* Call DOS to get an interrupt vector. */
+void __far *DOSGetIntVec( BYTE bIntNo );
+#pragma aux DOSGetIntVec =  \
+    "mov    ah, 35h"        \
+    "int    21h"            \
+    parm [al] value [es bx];
+
+/* Call DOS to set an interrupt vector. */
+void DOSSetIntVec( BYTE bIntNo, void __far *NewVector );
+#pragma aux DOSSetIntVec =  \
+    "mov    ah, 25h"        \
+    "push   ds"             \
+    "push   es"             \
+    "pop    ds"             \
+    "int    21h"            \
+    "pop    ds"             \
+    parm [al] [es dx];
+
+
+/* Ordinal of the repaint callback in USER. Of course undocumented. */
+#define REPAINT_ORDINAL     275
+
+/* Fun times. Undocumented function to create a writable alias of a code
+ * selector. In MS KB Q67165, Microsoft claimed that the function "is not
+ * documented and will not be supported in future versions of Windows".
+ * Clearly they lied, as it happily works on Win9x.
+ */
+extern UINT WINAPI AllocCStoDSAlias( UINT selCode );
+
+/* Internal function to install INT 2Fh hook. */
+void HookInt2Fh( void )
+{
+    WORD                selAlias;
+    void __far * __far  *OldInt2FhAlias;    /* This is fun! */
+
+    /* If not already set, get repaing callback from USER. */
+    if( !RepaintFunc ) {
+        HMODULE hMod;
+
+        hMod = GetModuleHandle( "USER" );
+        RepaintFunc = GetProcAddress( hMod, (LPCSTR)REPAINT_ORDINAL );
+    }
+    dbg_printf( "HookInt2Fh: RepaintFunc=%WP\n", RepaintFunc );
+
+    /* Now hook INT 2Fh. Since the address of the previous INT 2Fh handler
+     * is in the code segment, we have to create a writable alias. Just
+     * a little tricky.
+     */
+    selAlias = AllocCStoDSAlias( (__segment)&OldInt2Fh );
+
+    SwitchFlags |= INT_2F_HOOKED;
+    /* Build a pointer to OldInt2Fh using the aliased selector. */
+    OldInt2FhAlias = selAlias :> (WORD)&OldInt2Fh;
+    *OldInt2FhAlias = DOSGetIntVec( 0x2F );
+    DOSSetIntVec( 0x2F, SWHook );
+
+    FreeSelector( selAlias );
+}
+
+/* Internal function to unhook INT 2Fh. */
+void UnhookInt2Fh( void )
+{
+    if( SwitchFlags & INT_2F_HOOKED ) {
+        /* We have INT 2Fh hooked, undo that. */
+        SwitchFlags &= ~INT_2F_HOOKED;
+        DOSSetIntVec( 0x2F, OldInt2Fh );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sswhook.asm	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,126 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Copyright (c) 2012-2022  Michal Necasek
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Screen switching hook written in assembler.
+
+; See minidrv.h for more.
+SCREEN_SWITCH_OUT	equ	4001h
+SCREEN_SWITCH_IN    	equ	4002h
+
+; Defined by us, must match minidrv.h
+PREVENT_SWITCH		equ	80h
+
+; Carry flag bit on the stack
+FLAG_CF			equ	0001h
+
+public	_OldInt2Fh
+public	SWHook_
+
+; Callbacks written in C
+extrn	SwitchToBgnd_ : far
+extrn	SwitchToFgnd_ : far
+
+_DATA   segment public 'DATA'
+
+; Defined in C code
+extrn   _SwitchFlags : byte
+
+; Dispatch table. Only used locally.
+dsp_tbl	label	word
+	dw	SwitchToBgnd_	; SCREEN_SWITCH_OUT handler
+	dw	SwitchToFgnd_	; SCREEN_SWITCH_IN handler
+
+_DATA   ends
+
+DGROUP  group   _DATA
+
+_TEXT   segment public 'CODE'
+
+; Defined in code segment so that we can chain to the old interrupt
+; handler without needing to mess with DS.
+_OldInt2Fh	dd	0
+
+	.386
+
+; Screen switching hook for INT 2Fh. We need to handle screen switch
+; notifications ourselves and let the previous handler deal with the
+; rest.
+SWHook_	proc	far
+
+	; Cannot assume anything
+	assume	ds:nothing, es:nothing
+
+	; Check if the subfunction is one of those we're
+	; interested in and chain to previous handler if not.
+	cmp	ax, SCREEN_SWITCH_OUT
+	jz	handle_fn
+	cmp	ax, SCREEN_SWITCH_IN
+	jz	handle_fn
+	jmp	_OldInt2Fh		; Registers undisturbed (except flags)
+
+	; We are going to handle this interrupt and not chain.
+handle_fn:
+	push	ds			; Save what we can
+	pushad
+
+	; Establish data segment addressing
+	mov	bx, _DATA		; We'll overwrite BX later
+	mov	ds, bx
+	assume	ds:DGROUP
+
+	mov	bx, ax			; We will need the function later
+	mov	bp, sp			; So we can address stack
+
+	; See if switching is disabled
+	mov	al, _SwitchFlags
+	test	al, PREVENT_SWITCH
+	jz	dispatch		; If not set, do do the work
+
+	; It's disabled; set carry flag and return.
+
+	; To get to the saved flags, we need to skip the
+	; return address (4 bytes), saved DS (2 bytes), and
+	; saved registers (8 * 4 bytes)
+FLG_OFS	equ	4 + 2 + 8 * 4
+
+	or	word ptr [bp + FLG_OFS], FLAG_CF
+	jmp	exit
+
+	; Screen switching is not disabled; clear carry flag,
+	; process the screen switch notification, and return.
+dispatch:
+	and	word ptr [bp + FLG_OFS], NOT FLAG_CF
+	and	bx, 2			; Bit 1 of the subfunction
+	call	dsp_tbl[bx]		; Call handler in C
+
+exit:
+	popad				; Restore and return
+	pop	ds
+	iret
+
+SWHook_	endp
+
+
+_TEXT	ends
+	end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/winhack.h	Sun Jun 19 17:39:17 2022 +0200
@@ -0,0 +1,18 @@
+/* The gdidefs.h header badly conflicts with windows.h. Microsoft's printer
+ * drivers in the Windows DDK solve that by manually defining a large subset
+ * of windows.h. We solve that by including the normal windows.h but hiding
+ * the conflicting definitions.
+ */
+#define NOGDI
+#define PPOINT  n_PPOINT
+#define LPPOINT n_LPPOINT
+#define RECT    n_RECT
+#define PRECT   n_PRECT
+#define LPRECT  n_LPRECT
+#include <windows.h>
+#undef  PPOINT
+#undef  LPPOINT
+#undef  RECT
+#undef  PRECT
+#undef  LPRECT
+