Windows 3.1 and Windows NT 3.51 on Fujitsu Siemens S210 thin client

0.00 avg. rating (0% score) - 0 votes

My Fujitsu S210 thin client, bought in 2022, is still working well on Windows 98, with drivers for the SIS315E graphics card, VT8233 sound card and VT6102 Ethernet adapter. Still, I missed the Windows 3.1 user interface and decided to get it fully working on Windows 3.1 once again. When I tried in 2022, although I was able to get SVGA (1024×768) to work, I could not find any working Windows 3.1 drivers for the VT8233 AC97 codec or the LAN card and gave up.

Three years later, the situation has changed. There are now quite a few options for sound blaster emulation for DOS. Using Baron-von-Riedesel’s VSBHDA, a Sound Blaster and MPU401 emulator, my sound card (VT8233) was detected right away and Adlib’s TEST.EXE worked fine:

IMG_5079

Although DOSMID crashed when used with VSBHDA, GSPLAY1 worked out of the box:

IMG_5080

Audio in DOS games such as Prince of Persia 2, Super Angelo, Charlie the Duck or Charlie II worked fine. Prince of Persia 1.3 would hang if Sound Blaster was selected for audio output, but would work in MT32 mode. For the life of me I couldn’t find out what the problem was. I tried multiple versions of Prince of Persia 1 but the exact same issue persisted.

VSBHDA Sound Blaster emulation in Windows

Because VSBHDA required the JEMMEX memory manager, which did not implement the GEMMIS API, I had to run Windows in standard mode to get the emulated Sound Blaster 16 working. If the default Sound Blaster driver installer doesn’t work on your setup, try to install the drivers on DOSBox, extract the relevant SYSTEM.INI entries, and copy it to your S210. Of note, VerifyInt=0 may need to be added to SYSTEM.INI, otherwise card initialization may fail.

Initially I encountered noisy audio using VSBHDA 1.8 driver on Windows. The author was very helpful and provided detailed instructions for me to compile a patched version of the driver using OpenWatcom 1.9. With the patch, I was finally able to get audio to play properly in Windows.

This screenshot shows MIDI playback using MediaSauce player. WinProbe is in the background showing sound card configuration. The WAV/MIDI/CD tabs worked well, while the Video tab would hang Windows as soon as video playback was attempted. I suspect it didn’t like my standard mode setup.

NEW-2

To further improve MIDI playback quality, install FM MIDI Synth driver Version 2.14 by Jamie O’Connell. Otherwise, on some MIDI files, many notes won’t be audible using the default MIDIMAP.CFG that comes with the Sound Blaster 16 driver.

In Windows 3.1, only one application can use the sound card for PCM playback at any time. Trying to use MediaSauce to play WAV files with IIS WinPlay3 already running will result in an error. It would work however if you play MIDI in MediaSauce and MP3 in IIS WinPlay3.

NEW-4

When I first got the emulated Sound Blaster to work in Windows, mono WAV/MP3 files would play normally while stereo files would play twice as fast, as if the sampling rate had been doubled. The same WAV file would play correctly using Creative’s sample player. It took me a while to trace this behaviour to the mono output of the Sound Blaster 2.0 card. Likely, playing a stereo file (2 channels) will result in the driver dumping PCM audio data on the only output channel on the card, making it look as if the sampling rate had been doubled. I fixed the issue by installing the Sound Blaster 16 driver. Take note that the Sound Blaster 16 DOS installer (which installs the Windows drivers too) requires at least 600KB of free conventional memory; otherwise it might crash complaining “out of memory” when modifying Windows configuration.

Networking in Windows 3.11

After some searching I was able to find the Windows 3.1 driver for the VT6102 network card. Microsoft TCP/IP-3.2b then installed successfully. Internet Explorer 3.0 and Samba file sharing also worked well. However, my Windows network driver then refused to load in standard mode and I needed to create different CONFIG.SYS menu to load Windows in standard or enhanced mode to use either VSBHDA sound or networking.

IMG_5066

This is IE 3.0 in enhanced mode, showing www.textfiles.com. WS-FTP is connected to my home FTP server. I have no issues browsing Samba shares using Total Commander:

NEW6

There is this weird issue with the driver for our VIA Ethernet adapter. Once in a while, the NDIS driver will refuse to initialize, complaining about an error in PROTOCOL.INI. To recover, one must disconnect power to the thin client, disconnect the LAN cable, and press the POWER button a few times to discharge any redisual voltage, before powering it on again. A mere warm reboot will not work. The issue will usually happen after I switch between DOS, Windows 3.1, Windows 98, and Windows NT 3.51 in quick succession. Likely one of the drivers has set one or more flags which does not get cleared and results in the card being stuck in an undefined state until a cold reboot.

The screenshot below shows the issue as it occured on the NDIS2 DOS driver. If the issue happens in Windows 3.1, Windows will complain that the card cannot be detected. I have not seen this issue on Windows 98 or NT 3.51.

IMG_5113

Starting Windows with the Microsoft Network Client 3.0 for DOS fully loaded (e.g. with all the net initialize stuff) will result in an error: “Invalid VxD dynamic link call to device number 0028, service 8031. Your Windows configuration is invalid”. You should not load both the Windows 3.11 and DOS network stack at the same time. If the Windows 3.11 network stack is loaded, AUTOEXEC.BAT should only contain a single “net start” line, leaving the rest to Windows. I guess for this reason Windows setup loves to comment out any lines in AUTOEXEC.BAT which it thinks are trying to initialize the network, marking those with “REM – By Windows Setup”. In all likelihood, this will just mess up your AUTOEXEC.BAT and CONFIG.SYS, especially if MS-DOS multiple configuration is used.

IMG_5122

Standard mode in Windows 3.11 for Workgroups 

By default, Windows 3.11 for Workgroups will not run in standard mode, only enhanced mode. To force it to run in either standard mode or enhanced mode, copy WIN.COM, SYSTEM\DSWAP.EXE, SYSTEM\SWAP.EXE from a Windows 3.1 installation, as well as SYSTEM\DOSX.EXE from the Win31 subfolder of VSBHDA package, and overwrite the original files. Then set 286grabber=vgacolor.ini in SYSTEM.INI. Take note that WIN.COM may be reverted to the original version if you run Windows Setup, either from within Windows or by running SETUP.EXE, causing the ability to run standard mode to be lost. Occasionally, if running an MS-DOS session in 286 standard mode results in Jemmex exception 06, you might need to reboot the machine.

IMG_5058

I tried using Trumpet Winsock with WINPKT.COM on top of the DOS packet driver to access the network in standard mode. Unfortunately, although Trumpet is able to communicate with WINPKT.COM and the packet driver, showing the correct MAC address, pinging any IP would just timed out. I tweaked many settings such as IRQ or DMA channel but still could not get any response from ping.

Configuring VGA driver

PluMGMK‘s modern SVGA driver for Windows 3.1 worked well on my S210 in enhanced mode. In standard mode, it worked fine insofar as the Program Manager was able to display 1280×1024, the maximum supported resolution. However, the system froze after around 15 seconds whenever I played any audio file using VSBHDA driver. I suspected this was likely interrupt or DMA related, but did not have the time to probe this further. After installing this driver, my Windows 3.1’s SETUP.EXE program also started to complain about insufficient memory while changing options. To fix this, I had to delete old OEMxxx.INF files in C:\WINDOWS (which were copies of old graphic drivers). Eventually, I decided to just use Microsoft’s generic SVGA driver for Windows 3.1, supporting up to 1024x768x256.

With the SVGA driver, Encarta 95 worked well, allowing me to read tens of thousands of articles. Here you can see how it did not have an article for the Internet, which didn’t become popular until the mid 1990s. CalmiraXP is also installed, not for the Windows XP interface, but just to give me a taskbar to conveniently switch between running programs. For this reason I did not set CalmiraXP as the default program manager, like what the manual suggested.

NEW5

Adding a second storage device

I tried to install NT 3.51 on a new partition on the CF card and triple-boot with DOS 6.22 and Windows 98. This created a mess as neither DOS 6.22, NT 3.51 or Windows 98 would be happy if its partition is located beyond the 8GB barrier. I eventually decided to just leave MS-DOS 6.22 and Windows 98 alone and install NT 3.51 on its own disk drive.

There is a 40-pin IDE connector on the board for me to install an additional disk. There is however no dedicated pin to tap 5V from. Although there is a 5V connector near the PCI slot which outputs 5V, its current capability is very low. In the end, I tapped 5V from the one of the pin on the PCI riser card, fed it to a CF-to-IDE adapter with another 32GB CF card:

IMG_4409

The new card was detected right away in BIOS. My S210 now has 2 x 32GB disk drives:

IMG_4410

The S210’s BIOS has options to configure HDD timing. I did not bother with this as my CF cards are just 133x (max speed 20MB/s). When tested using a card reader, the actual max speed is around 14-15MB/s. Bandwidth limit for Fast PIO (the default option) is around 16MB/s.

PXL_20230102_081041191

On a side note, the PCI slot on this board does not supply 12V or -12V. A parallel port PCI card would work, while a serial port card (which needs -12V) or a sound card (which needs 12V for the amplifier) might have issues.

Although this BIOS can boot from a USB CD/DVD drive, it can only do so in floppy mode, as the emulated drive will not appear on the IDE bus. To cater for this, I routed the IDE cable for the secondary slave IDE channel through the PCI slot, allowing me to conveniently connect an IDE CD-ROM if needed. I am not planning to use the PCI slot anytime soon.

IMG_5086

When I played with the S210 in 2022, legacy USB support for hard disk drives was flaky and would not work well unless booting from a USB floppy drive. It took me three years to find out that the issues were most likely due to some corrupted BIOS configuration. The issue disappeared after I reset the BIOS settings from the Exit menu. USB thumbdrives are now recognized properly as IDE drives and work well in MS-DOS, Windows 3.1 and NT 3.51.

Installing Windows NT 3.51

I first installed Windows NT 3.51 SP5 on VirtualBox in IDE mode using the bootable ISO from here. Then, I used VBoxManage to convert the disk to raw, and used Win32DiskImage to write the image to the CF card. To make use of the full 32GB space on the CF card, only a 2GB NTFS partition was created during installation. PQMAGIC for DOS was later used to extend this partition to 32GB. NT 3.51 installer only supports NTFS partitions up to 4GB, but once installed, NT 3.51 can run off 32GB without issues. There is a delay of 15 seconds at boot but after that it works fine:

IMG_5070

It goes without saying that you should not use modern tools (GParted, CloneZilla, NTFS-3G or even Windows XP) to work with NT 3.51 NTFS. If you are lucky, it will just complain that the NTFS version (1.1) is not supported. If you are not, it will attempt to upgrade the partition to the latest NTFS format, making your data unreadable to Windows NT 3.51.

SIS315E comes with NT 4.0 drivers but not NT 3.51. You can tell this by the lack of OEMSETUP.INF in the driver folder. However, using VBEMP for Windows NT 3.51, I was able to get 1280×1024 with 16-bit colors. Take note that FRAMEBUF.DLL might need to be copied to the Windows directory for the driver to work.

NEW7

Setting up networking was a breeze using VT6102 NT 3.51’s driver. Web browsing, file sharing, and FTP worked well too. Netscape Communicator 4.5 32-bit worked fine, showing http://web.textfiles.com

NEW10

Now that Windows NT 3.51 is on the second hard drive, I use GRUB4DOS to allow me to select which OS to boot from without tweaking the BIOS. I did not have any E-IDE issues (like what I encountered on the Pocket 386), since the BIOS on the S210 is presumably much more modern:

IMG_5065

This is the partition structure I used. The first CF card contains DOS 6.22 (FAT16 primary), Windows 98 (FAT32 primary), and an extended data partition (FAT32). The second CF card contains a FAT16 primary data partition (which DOS 6.22 can see), a NTFS primary partition (for NT 3.51) and a FAT32 data partition (for extra storage under Windows 98). GRUB4DOS is configure to hide/unhide the primary partitions depending on which OS is selected for booting

pqmagic

Patching VT8233 driver for NT 3.51

There is a Windows NT 3.51 driver for the Windows 8233 which just needs to be installed from Control Panel > Drivers to enable sound support. Or so I thought. Unfortunately, attempting to install the driver returned the following error message:

“Insufficient system resources exist to complete the requested service.”

Now, you should not read too much into this and start to probe DMA, IRQ or even conventional memory, like what I did. All it means is that the kernel mode driver (VIAUDIO.SYS) has decided to return code 0xC000009A (STATUS_INSUFFICIENT_RESOURCES) from DriverEntry, causing Windows to display the above user-friendly (but generic) error message. In other words, it just means the driver initialization failed for some reasons, not necessarily a lack of system resources.

Using the Interactive Disassembler (IDA) v5.2, I generated the assembly listing for the VIAUDIO.SYS driver. This is the DriverEntry function, with auto-comment enabled to make it easier to understand the code:

INIT:000182C0 ;	Attributes: bp-based frame
INIT:000182C0
INIT:000182C0 ;	__stdcall DriverEntry(x, x)
INIT:000182C0 public _DriverEntry@8
INIT:000182C0 _DriverEntry@8 proc near
INIT:000182C0
INIT:000182C0 P= dword ptr -8
INIT:000182C0 var_4= dword ptr -4
INIT:000182C0 arg_0= dword ptr	8
INIT:000182C0 arg_4= dword ptr	0Ch
INIT:000182C0
INIT:000182C0 push    ebp
INIT:000182C1 mov     eax, [esp+arg_0]
INIT:000182C5 mov     ebp, esp
INIT:000182C7 sub     esp, 8	      ;	Integer	Subtraction
INIT:000182CA mov     dword ptr	[eax+34h], offset _SoundUnload@4 ; SoundUnload(x)
INIT:000182D1 push    esi
INIT:000182D2 mov     ecx, offset _SoundDispatch@8 ; SoundDispatch(x,x)
INIT:000182D7 push    edi
INIT:000182D8 mov     [ebp+var_4], eax
INIT:000182DB xor     edi, edi	      ;	Logical	Exclusive OR
INIT:000182DD mov     [eax+38h], ecx
INIT:000182E0 mov     [ebp+P], edi
INIT:000182E3 mov     [eax+40h], ecx
INIT:000182E6 mov     [eax+70h], ecx
INIT:000182E9 mov     [eax+44h], ecx
INIT:000182EC lea     edx, [ebp+P]    ;	Load Effective Address
INIT:000182EF mov     [eax+48h], ecx
INIT:000182F2 push    edx	      ;	int
INIT:000182F3 mov     [eax+80h], ecx
INIT:000182F9 mov     dword ptr	[eax+78h], offset _SoundShutdown@8 ; SoundShutdown(x,x)
INIT:00018300 push    offset _SoundCardInstanceInit@8 ;	int
INIT:00018305 push    offset ??_C@_1BG@KEAJ@?$AAP?$AAa?$AAr?$AAa?$AAm?$AAe?$AAt?$AAe?$AAr?$AAs?$AA?$AA?$AA?$AA?$AA?$AH?$AA?$AA?$AA?$AA?$AA?$AA?7_?$AE_?$AA?$BG?$AA?$AB@	; "Parameters"
INIT:0001830A push    [ebp+arg_4]     ;	int
INIT:0001830D call    _SoundEnumSubkeys@16 ; SoundEnumSubkeys(x,x,x,x)
INIT:00018312 mov     esi, eax
INIT:00018314 cmp     [ebp+P], edi    ;	Compare	Two Operands
INIT:00018317 jz      short loc_1833A ;	Jump if	Zero (ZF=1)
INIT:00018319 mov     edi, [ebp+P]
INIT:0001831C
INIT:0001831C loc_1831C:	      ;	ValueData
INIT:0001831C push    dword ptr	[edi+0A74h]
INIT:00018322 push    offset ??_C@_1CI@CPHG@?$AAC?$AAo?$AAn?$AAf?$AAi?$AAg?$AAu?$AAr?$AAa?$AAt?$AAi?$AAo?$AAn?$AA?5?$AAE?$AAr?$AAr?$AAo?$AAr?$AA?$AA@ ;	"Configuration Error"
INIT:00018327 push    dword ptr	[edi+0A70h] ; Path
INIT:0001832D call    _SoundWriteRegistryDWORD@12 ; SoundWriteRegistryDWORD(x,x,x)
INIT:00018332 mov     edi, [edi+4]
INIT:00018335 cmp     edi, [ebp+P]    ;	Compare	Two Operands
INIT:00018338 jnz     short loc_1831C ;	Jump if	Not Zero (ZF=0)
INIT:0001833A
INIT:0001833A loc_1833A:	      ;	Logical	Compare
INIT:0001833A test    esi, esi
INIT:0001833C jge     short loc_18350 ;	Jump if	Greater	or Equal (SF=OF)
INIT:0001833E cmp     [ebp+P], 0      ;	Compare	Two Operands
INIT:00018342 jz      short loc_1834C ;	Jump if	Zero (ZF=1)
INIT:00018344 push    [ebp+P]	      ;	P
INIT:00018347 call    _SoundCleanup@4 ;	SoundCleanup(x)
INIT:0001834C
INIT:0001834C loc_1834C:
INIT:0001834C mov     eax, esi
INIT:0001834E jmp     short loc_18352 ;	Jump
INIT:00018350
INIT:00018350 loc_18350:	      ;	Logical	Exclusive OR
INIT:00018350 xor     eax, eax
INIT:00018352
INIT:00018352 loc_18352:
INIT:00018352 pop     edi
INIT:00018353 pop     esi
INIT:00018354 mov     esp, ebp
INIT:00018356 pop     ebp
INIT:00018357 retn    8		      ;	Return Near from Procedure
INIT:00018357 _DriverEntry@8 endp

Searching the listing file, I located 12 instances where the driver might return 0x0C000009A (STATUS_INSUFFICIENT_RESOURCES). Many of these belonged to mixer or MIDI setup methods, which wouldn’t be called during initial initialization. The most suspicious instance was in _SoundCardInstanceInit, which was called from DriverEntry:

INIT:000183BD public _SoundCardInstanceInit@8
INIT:000183BD _SoundCardInstanceInit@8 proc near
INIT:000183BD
INIT:000183BD ValueData= byte ptr -0B8h
INIT:000183BD var_B4= dword ptr	-0B4h
INIT:000183BD var_B0= dword ptr	-0B0h
INIT:000183BD var_AC= dword ptr	-0ACh
INIT:000183BD var_A8= dword ptr	-0A8h
INIT:000183BD var_A4= dword ptr	-0A4h
INIT:000183BD var_A0= dword ptr	-0A0h
INIT:000183BD var_9C= dword ptr	-9Ch
INIT:000183BD var_94= byte ptr -94h
INIT:000183BD var_4= dword ptr -4
INIT:000183BD arg_0= dword ptr	8
INIT:000183BD arg_4= dword ptr	0Ch
INIT:000183BD
INIT:000183BD push    ebp
INIT:000183BE mov     ebp, esp
INIT:000183C0 sub     esp, 0B8h	      ;	Integer	Subtraction
INIT:000183C6 push    ebx
INIT:000183C7 push    esi
INIT:000183C8 push    edi
INIT:000183C9 push    206B6444h	      ;	Tag
INIT:000183CE push    0C20h	      ;	NumberOfBytes
INIT:000183D3 push    0		      ;	PoolType
INIT:000183D5 call    ds:__imp__ExAllocatePoolWithTag@12 ; ExAllocatePoolWithTag(x,x,x)
INIT:000183DB mov     esi, eax
INIT:000183DD test    esi, esi	      ;	Logical	Compare
INIT:000183DF jnz     short loc_183EB ;	Jump if	Not Zero (ZF=0)
INIT:000183E1 mov     eax, 0C000009Ah
INIT:000183E6 jmp     loc_18632	      ;	Jump
INIT:000183EB
INIT:000183EB loc_183EB:
INIT:000183EB mov     edi, esi
INIT:000183ED xor     eax, eax	      ;	Logical	Exclusive OR
INIT:000183EF mov     ecx, 308h
INIT:000183F4 rep stosd		      ;	Store String
INIT:000183F6 mov     eax, ??_C@_04DIHA@GDI?5?$AA@ ; `string'
INIT:000183FB lea     edi, [esi+2B0h] ;	Load Effective Address
INIT:00018401 mov     [esi], eax
INIT:00018403 mov     eax, [ebp+arg_0]
INIT:00018406 mov     ecx, ??_C@_04KBND@Hw?5?5?$AA@ ; `string'
INIT:0001840C mov     ebx, [ebp+arg_4]
INIT:0001840F push    2		      ;	Level
INIT:00018411 mov     [edi], ecx
INIT:00018413 mov     [esi+0A70h], eax
INIT:00018419 lea     eax, [esi+30h]  ;	Load Effective Address
INIT:0001841C mov     byte ptr [esi+72h], 55h
INIT:00018420 mov     byte ptr [esi+71h], 55h
INIT:00018424 mov     ecx, [ebx+4]
INIT:00018427 push    eax	      ;	Mutex
INIT:00018428 mov     [esi+98h], ecx
INIT:0001842E call    ds:__imp__KeInitializeMutex@8 ; KeInitializeMutex(x,x)
INIT:00018434 push    1		      ;	Level
INIT:00018436 lea     ecx, [esi+50h]  ;	Load Effective Address
INIT:00018439 push    ecx	      ;	Mutex
INIT:0001843A call    ds:__imp__KeInitializeMutex@8 ; KeInitializeMutex(x,x)
INIT:00018440 push    3		      ;	Level
INIT:00018442 lea     ecx, [esi+2C0h] ;	Load Effective Address
INIT:00018448 push    ecx	      ;	Mutex
INIT:00018449 call    ds:__imp__KeInitializeMutex@8 ; KeInitializeMutex(x,x)
INIT:0001844F mov     ecx, [ebx]
INIT:00018451 test    ecx, ecx	      ;	Logical	Compare
INIT:00018453 jnz     short loc_1845A ;	Jump if	Not Zero (ZF=0)
INIT:00018455 mov     [esi+4], esi
INIT:00018458 jmp     short loc_18463 ;	Jump
INIT:0001845A
INIT:0001845A loc_1845A:
INIT:0001845A mov     eax, [ecx+4]
INIT:0001845D mov     [ecx+4], esi
INIT:00018460 mov     [esi+4], eax
INIT:00018463
INIT:00018463 loc_18463:	      ;	Load Effective Address
INIT:00018463 lea     eax, [esi+0Ch]
INIT:00018466 mov     [ebx], esi
INIT:00018468 push    eax	      ;	int
INIT:00018469 push    5		      ;	BusType
INIT:0001846B call    _SoundGetBusNumber@8 ; SoundGetBusNumber(x,x)
INIT:00018470 test    eax, eax	      ;	Logical	Compare
INIT:00018472 jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018478 mov     dword ptr	[esi+8], 5
INIT:0001847F mov     dword ptr	[ebp+ValueData], 220h
INIT:00018489 mov     [ebp+var_B4], 388h
INIT:00018493 mov     [ebp+var_B0], 7
INIT:0001849D mov     [ebp+var_A4], 2000h
INIT:000184A7 mov     [ebp+var_A0], 330h
INIT:000184B1 mov     eax, 0FFFFFFFFh
INIT:000184B6 push    esi
INIT:000184B7 mov     [ebp+var_AC], eax
INIT:000184BD mov     [ebp+var_A8], eax
INIT:000184C3 xor     eax, eax	      ;	Logical	Exclusive OR
INIT:000184C5 mov     [ebp+var_9C], eax
INIT:000184CB mov     byte ptr [ebp+var_4], al
INIT:000184CE call    _PCITest@4      ;	PCITest(x)
INIT:000184D3 test    al, al	      ;	Logical	Compare
INIT:000184D5 jnz     short loc_184E1 ;	Jump
INIT:000184D7 mov     eax, 0C000009Ah
INIT:000184DC jmp     loc_18632	      ;	Jump
INIT:000184E1
INIT:000184E1 loc_184E1:
INIT:000184E1 mov     ax, [esi+0A80h]
INIT:000184E8 cmp     ax, 0FFFFh      ;	Compare	Two Operands
INIT:000184EC jnz     short loc_184FA ;	Jump if	Not Zero (ZF=0)
INIT:000184EE mov     [ebp+var_A0], 0FFFFFFFFh
INIT:000184F8 jmp     short loc_18503 ;	Jump
INIT:000184FA
INIT:000184FA loc_184FA:	      ;	Move with Zero-Extend
INIT:000184FA movzx   eax, ax
INIT:000184FD mov     [ebp+var_A0], eax
INIT:00018503
INIT:00018503 loc_18503:
INIT:00018503 mov     eax, [esi+24h]
INIT:00018506 mov     [ebp+var_B0], eax
INIT:0001850C push    esi
INIT:0001850D movzx   ecx, word	ptr [esi+0A78h]	; Move with Zero-Extend
INIT:00018514 mov     dword ptr	[ebp+ValueData], ecx
INIT:0001851A mov     edx, [esi+28h]
INIT:0001851D mov     [ebp+var_AC], edx
INIT:00018523 mov     eax, [esi+2Ch]
INIT:00018526 mov     [ebp+var_A8], eax
INIT:0001852C call    _HwInitialize@4 ;	HwInitialize(x)
INIT:00018531 push    0
INIT:00018533 push    esi
INIT:00018534 call    _SBCreateDevice@8	; SBCreateDevice(x,x)
INIT:00018539 test    eax, eax	      ;	Logical	Compare
INIT:0001853B jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018541 push    1
INIT:00018543 push    esi
INIT:00018544 call    _SBCreateDevice@8	; SBCreateDevice(x,x)
INIT:00018549 test    eax, eax	      ;	Logical	Compare
INIT:0001854B jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018551 push    4
INIT:00018553 push    esi
INIT:00018554 call    _SBCreateDevice@8	; SBCreateDevice(x,x)
INIT:00018559 test    eax, eax	      ;	Logical	Compare
INIT:0001855B jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018561 push    5
INIT:00018563 push    esi
INIT:00018564 call    _SBCreateDevice@8	; SBCreateDevice(x,x)
INIT:00018569 test    eax, eax	      ;	Logical	Compare
INIT:0001856B jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018571 push    6
INIT:00018573 push    esi
INIT:00018574 call    _SBCreateDevice@8	; SBCreateDevice(x,x)
INIT:00018579 test    eax, eax	      ;	Logical	Compare
INIT:0001857B jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018581 push    dword ptr	[esi+7Ch] ; DeviceObject
INIT:00018584 call    ds:__imp__IoRegisterShutdownNotification@4 ; IoRegisterShutdownNotification(x)
INIT:0001858A test    eax, eax	      ;	Logical	Compare
INIT:0001858C jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:00018592 mov     byte ptr [esi+1Dh], 1
INIT:00018596 lea     eax, [ebp+ValueData] ; Load Effective Address
INIT:0001859C push    eax	      ;	int
INIT:0001859D push    esi	      ;	ServiceContext
INIT:0001859E call    _SoundInitHardwareConfig@8 ; SoundInitHardwareConfig(x,x)
INIT:000185A3 test    eax, eax	      ;	Logical	Compare
INIT:000185A5 jl      loc_18632	      ;	Jump if	Less (SF!=OF)
INIT:000185AB push    edi
INIT:000185AC lea     eax, [esi+0A0h] ;	Load Effective Address
INIT:000185B2 push    offset _SoundQueryFormat@8 ; SoundQueryFormat(x,x)
INIT:000185B7 push    1
INIT:000185B9 push    eax
INIT:000185BA call    _SoundInitializeWaveInfo@16 ; SoundInitializeWaveInfo(x,x,x,x)
INIT:000185BF mov     eax, [esi+94h]
INIT:000185C5 test    eax, eax	      ;	Logical	Compare
INIT:000185C7 jz      short loc_185DF ;	Jump if	Zero (ZF=1)
INIT:000185C9 push    [ebp+var_4]
INIT:000185CC lea     ecx, [ebp+var_94]	; Load Effective Address
INIT:000185D2 push    ecx
INIT:000185D3 push    dword ptr	[eax+28h]
INIT:000185D6 call    _SoundMixerInit@12 ; SoundMixerInit(x,x,x)
INIT:000185DB test    eax, eax	      ;	Logical	Compare
INIT:000185DD jl      short loc_18632 ;	Jump if	Less (SF!=OF)
INIT:000185DF
INIT:000185DF loc_185DF:
INIT:000185DF mov     eax, [esi+0B0h]
INIT:000185E5 mov     cl, [esi+346h]
INIT:000185EB cmp     dword ptr	[esi+338h], 1 ;	Compare	Two Operands
INIT:000185F2 push    eax	      ;	int
INIT:000185F3 push    ecx	      ;	char
INIT:000185F4 sbb     al, al	      ;	Integer	Subtraction with Borrow
INIT:000185F6 inc     al	      ;	Increment by 1
INIT:000185F8 push    eax	      ;	char
INIT:000185F9 push    [ebp+var_A0]    ;	int
INIT:000185FF push    [ebp+var_B0]    ;	int
INIT:00018605 push    [ebp+var_A8]    ;	int
INIT:0001860B push    [ebp+var_AC]    ;	int
INIT:00018611 push    dword ptr	[ebp+ValueData]	; ValueData
INIT:00018617 push    dword ptr	[esi+0A70h] ; Path
INIT:0001861D call    _SoundSaveConfig@36 ; SoundSaveConfig(x,x,x,x,x,x,x,x,x)
INIT:00018622 test    eax, eax	      ;	Logical	Compare
INIT:00018624 jl      short loc_18632 ;	Jump if	Less (SF!=OF)
INIT:00018626 mov     dword ptr	[esi+0A74h], 0FFFFFFFFh
INIT:00018630 xor     eax, eax	      ;	Logical	Exclusive OR
INIT:00018632
INIT:00018632 loc_18632:
INIT:00018632 pop     edi
INIT:00018633 pop     esi
INIT:00018634 pop     ebx
INIT:00018635 mov     esp, ebp
INIT:00018637 pop     ebp
INIT:00018638 retn    8		      ;	Return Near from Procedure
INIT:00018638 _SoundCardInstanceInit@8 endp

ExAllocatePoolWithTag would only fail if there was not enough memory. But since only 0C20h (3104) bytes were requested, a failure here was highly unlikely. The next candidate was the call to PCITest(), which would return true if the card was detected (the test al, al instruction made it obvious that the return was boolean). The driver initialization would halt immediately if the card was not detected. According to this Windows NT 3.51 article, there was a PCI enumeration bug on Windows NT 3.51, albeit for SCSIPORT.SYS. Maybe my situation was similar and VIAUDIO.SYS just didn’t find what it wanted from the S210 PCI bus.

To test if this was indeed the case, I needed to patch _SoundCardInstanceInit to always proceed regardless of the result of PCITest by changing jnz to jmp:

INIT:000184B7 mov     [ebp+var_AC], eax
INIT:000184BD mov     [ebp+var_A8], eax
INIT:000184C3 xor     eax, eax	      ;	Logical	Exclusive OR
INIT:000184C5 mov     [ebp+var_9C], eax
INIT:000184CB mov     byte ptr [ebp+var_4], al
INIT:000184CE call    _PCITest@4      ;	PCITest(x)
INIT:000184D3 test    al, al	      ;	Logical	Compare
INIT:000184D5 jmp     short loc_184E1 ;	Jump
INIT:000184D7 mov     eax, 0C000009Ah
INIT:000184DC jmp     loc_18632	      ;	Jump

The next thing to do was to find out exactly where to perform the hex patch. To do this, I just used Biew to hex search for 88 03, a value which appears in the preceding instructions:

INIT:00018489 mov     [ebp+var_B4], 388h
INIT:00018493 mov     [ebp+var_B0], 7

Using Biew’s disasembler mode, instructions which resembled the IDA listing were located, highlighted in the screenshot below for clarity. It turned out that the raw offset was already shown in IDA listing, for example test al, al was listed at INIT:000184D3 for a raw offset of 0x84D3:

viaudio

To bypass the result of PCITest, patch 75 0A (JNE/JNZ) to EB 0A (JMP, always jump regardless of result):

viaudio2

For the patched driver to be usable, update the checksum of VIAUDIO.SYS using PECHKSUM.EXE. The updated checksum field can be viewed from CFF Explorer (00 01 2A 61 for the new driver):

Screenshot 2026-02-28 121043

Using Hex Comparison we can see where the checksum is actually located (hint: around offset 0xD0), by comparing the original and patched executable. The original checksum was 00 01 B4 60:

Screenshot 2026-02-28 121315

The following C code will also update the checksum of a PE executable, by using the MapFileAndCheckSum Win32 API:

int main() {
    DWORD headersum = 0;
    DWORD checksum = 0;

    if (MapFileAndCheckSumW(L"VIAUDIO.SYS", &headersum, &checksum) == CHECKSUM_SUCCESS) {
        printf("Old checksum: %08X\n", headersum);
        printf("New checksum: %08X\n", checksum);
    } else {
        printf("Checksum calculation failed\n");
    }

	getc(stdin);
    return 0;
}

To update the driver to the patched version, remove the old one from Control Panel > Drivers, reboot, and readd the new driver. If you do not reboot, Windows NT 3.51 may report that the driver has been successfully added while still using the old version.

After rebooting, I was finally able to hear the Windows startup sound! So it was indeed a PCI enumeration issue, making the driver think my card was not connected. The VIA AC97 Audio Controller entry now appeared in Control Panel > Drivers. If after patching your VIA sound card still cannot work, try to enable viaudio under Control Panel > Devices. Also check Administrative Tools > Event Viewer for any errors.

MIDI support on NT 3.51

VT8233’s NT 3.51 driver supports WAVE playback but not MIDI. I modified OEMSETUP.INF to use VIAMIDI.DLL from NT 4.0 but NT 3.51 kept complaining that the DLL was missing. The occurence of several MIDI methods in the NT 3.51 version of VIAUDIO.DLL, and the fact that the NT 4.0 driver does not require a kernel mode driver (e.g. VIAMIDI.SYS) to enable MIDI support suggests that it is perhaps not too hard to patch the NT 3.51 driver to at least get a few MIDI files to play. Likely, both the NT 3.51 and NT 4.0 drivers were compiled from the same codebase. However, the rudimentary nature of MIDI support in NT 3.51 might have resulted in the decision to exclude the MIDI interface from the production build for NT 3.51.

Meanwhile, WinGroove Player 0.9E worked well for MIDI playback. The MIDI synthesizer driver (WINGROOV.DRV) it came with did not work on NT 3.51, as it was a 16-bit driver designed for Windows 3.1.

NEW11

This is Yamaha SoftSynthesizer S-YXG50 running on NT 3.51. Despite what the user manual claimed, I could not get it to work as a system-wide MIDI synthesizer, although the built-in player worked fine. If the “Song” button does not work, drag and drop your MIDI files to the player instead. I did not have any such issues on Windows 98. MIDI just worked out of the box.

NEW-20

Multimedia software

With the audio driver installed, Netscape Communicator could finally play SWF Flash movies with audio using Shockwave Flash 6.0 r79 pluginDo not however associate the SWF extension with Netscape thinking you can just double click a SWF file to play in Netscape. Due to an intermediate conversion step in the playback process, associating SWF with Netscape will cause Netscape to be launched again and again whenever you open an SWF file.

NEW99

Microsoft Encarta 97 worked well on Windows NT 3.51. It finally contained articles for the Internet and related stuff such as TCP/IP:

NEW-200

In case you are wondering, Entarta 97 supports Windows 3.1 but refuses to install in standard mode. Encarta 96 installed in standard mode but crashed with “Abnormal Program Termination” on my S210. I could only get Encarta 95 to work well on my Windows 3.11 standard mode configuration. I guess I don’t need to read another article about the Internet using Windows 3.11 in standard mode on my S210.

This is Microsoft Encarta 97, Internet Explorer 3.0 and Winamp 2.64 running on my S210 at 1280×1024, with network and audio driver installed. IE is showing gopher://gopher.floodgap.com, one of the few remaining Gophers servers. NT Shell (not NewShell), a beta port of Calmira for Windows NT 3.51, is also installed. As a portable program, NT Shell still brings the taskbar to Windows NT 3.51 without messing with system files or changing the internal Windows version to NT 4.0. I didn’t bother with IE 5.0 for NT 3.51, which consumes a lot of resources and still can’t open most modern web pages anyway. There are better browsers (such as RetroZilla) out there.

NEW22222

MP3 playback works great in Winamp, although adding a directory to the playlist doesn’t work. You can still add many MP3 files in one go using multi-selection. I believe the feature uses SHBrowseForFolder which is only available in Windows 95 / NT 4.0. Well, at least it doesn’t crash.

Downloads

You can download the Windows 3.11 and Windows NT 3.51 drivers I used for my S210 here. Inside the archive you will find the patched VIAUDIO.SYS for NT 3.51 as well as the original file (renamed VIAUDIO_OLD.SYS, 61568 bytes, dated 16 September 2002). This version of VIADIO.SYS worked well with my S210. Several other versions of the same SYS file did not work, even with the PCITest patch applied.

The ZIP file also contains VSBHDA, Calmira, NT Shell, Netscape and the Flash player plugin for testing.

See also
Fujitsu Siemens FSC Futro S210 thin client

 

0.00 avg. rating (0% score) - 0 votes
ToughDev

ToughDev

A tough developer who likes to work on just about anything, from software development to electronics, and share his knowledge with the rest of the world.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>