As one step in the development of the Windows 3.x/2.x display driver, I needed to replace a BIOS INT 10h call to set the video mode with a “native” mode set code going directly to the (virtual) hardware registers. One big reason is that the (VBE 2.0) BIOS is limited to a predefined set of resolutions, whereas native mode set code can set more or less any resolution, enabling widescreen resolutions and such.
Replacing the code was not hard (I already had a working and tested mode set code) and it worked in Windows 3.1 and 3.0 straight away. When I got around to testing Windows 2.11, I noticed that although Windows looked fine and mouse worked, the keyboard didn’t seem to be working. Windows was just completely ignoring all keyboard input.
Curiously, the letters I fruitlessly typed in Windows popped up on the DOS command prompt as soon as I quit Windows (which was not hard using a mouse). This indicated that the keyboard input was not exactly lost, but it was not ending up in the right place somehow.
After double and triple checking, I assured myself that yes, using native display mode setting code instead of the BIOS broke the keyboard in Windows 2.11 (but not in Windows 3.x). That was, to put it mildly, not an anticipated side effect. How is that even possible?!
Fortunately I did not have to spend too much time figuring out the problem, but only because I had the Windows 2.11 DDK on hand, including the source code to KEYBOARD.DRV. And soon enough, there I found the following (excerpted) source code:
; ROM BIOS addresses CrtMode EQU 449H ; rom bios data area for screen mode ... ; When running Windows, it can happen that we will be interrupted by a popup ; in text mode that will read keyboard (Business Network). This very ; wierd case is detected by finding the screen in text mode (this is ; quite uncommon when this keyboard driver is activated). ; ifndef TEST ; IF you want to test this driver with the OEM keyboard test, ; TKEYBD.EXE, it must be assembled with the TEST flag set so ; that this code is NOT executed. cmp byte ptr ds:[CrtMode],4 ; text mode? jb jkbi0 ; yes, jump to ROM. endif
The code in the Windows 2.11 keyboard driver checks the
CrtMode byte at address 0:449h (current BIOS video mode) and if it’s less than 4, lets the ROM BIOS handle the keyboard input, bypassing Windows keyboard handling.
Said code is a bit sketchy. It does not consider mono mode 7, which is also a text mode. But more importantly, it makes the assumption that Windows must run in a graphics mode (reasonable) and that the BIOS must have been used to set the mode, changing the
CrtMode byte to a value 4 or higher (much less reasonable).
Interestingly, this clearly already broke the OEM keyboard test utility TKEYBD.EXE, which presumably in fact ran KEYBOARD.DRV in text mode.
I wondered how this works when Windows 2.11 runs with a Hercules graphics card (HGC), which does not use the BIOS to set the graphics mode (because there is no BIOS support). I could not find any code in the Hercules driver that would touch
CrtMode at all. Eventually I realized that the HGC would in fact run in mode 7, so the strange logic in KEYBOARD.DRV would not kick in. Did the Business Network pop-up problem not exist on Hercules cards? Who knows.
At any rate, now I had a good idea how to un-break the keyboard in Windows 2.11 with my display driver. I just added a line of code to write some more or less random value higher than 3 to 0:449h. And sure enough, suddenly the keyboard worked in Windows 2.11!
But that left me with a question what to do about Windows 3.x. Clearly Windows 3.x didn’t need
CrtMode to change (at least at first glance). But perhaps some obscure code would benefit if it did?
So I left the code in for all Windows versions. And poof, when Windows 3.1 started, I ended up with a black screen and a non-functional VM. The same happened with Windows 3.0, only not quite, because Windows 3.0 just instantly returned to DOS.
Except for Windows 3.0 in real mode, which worked fine. Then I realized that of course writing to 0:449h is dumb, because it can’t work in protected mode. Instead I needed to write to 40:49h, which works in both real and protected mode.
The excursion to Windows 2.11 KEYBOARD.DRV also allowed me to finally understand one rather strange fragment of code in the Windows 3.1 Video 7 sample driver (in the
physical_enable routine) that I previously removed:
mov ax,040h ; bogus for keyboard !!! mov es,ax mov BYTE PTR es:[49h],06h
This code writes the value 6 into the
CrtMode byte. The “bogus for keyboard !!!” comment is not exactly enlightening, to put it mildly. But seeing the KEYBOARD.DRV code, it makes sense that a display driver might need to write something there if it didn’t go through the BIOS to set the Windows graphics mode. In retrospect, perhaps I should not have removed that code…
On the other hand, I could not find any similar logic in the Windows 3.1 driver for the 8514/A, which also does not use the BIOS to set the mode. Which makes me think the issue was really specific to Windows 2.11 (or maybe more generally Windows 2.x).
Indeed checking the KEYBOARD.DRV source code in the Windows 3.1 DDK, one can find the following in the change history:
; 20 apr 89 peterbe Removed old comments above kbic: about ; Business Network and W.1.00 keyboard test.
In other words, the sketchy logic was removed from KEYBOARD.DRV before Windows 3.0 was released.
In a way I was lucky that I didn’t integrate the native mode set code right away, because figuring out why the keyboard does not work in Windows 2.11 would have been massively more difficult.
What’s the moral of the story? Having source code access can save a lot of time and head scratching, and good comments are important. The logic in Windows 2.11 KEYBOARD.DRV is rather strange and extremely non-obvious, but at least the comments explain why it’s there and the reader can understand what’s happening.
On the other hand, the “bogus for keyboard” comment in a display driver is impossible to to understand without context (that only exists well outside of the display driver), and it’s really no better than no comment at all.
The other takeaway is that 16-bit Windows is a house of cards built on a foundation of sand. An innocent change in one place can cause something to break in a seemingly completely unrelated location. Maintaining and debugging such a system is a nightmare. It also demonstrates that a flaky house of cards can still be a major commercial success.