USB flash drives on 8-bit ISA bus using CH375 ISB to USB adapter

5.00 avg. rating (93% score) - 1 vote

I purchased the CH375 ISA to USB adapter from Taobao, hoping for an easier way to transfer files to my PC XT clones. At a cost of 145 Chinese yuan (around US $23) per card, or approximately US $30 per card with shipping, this seems to be a very good price. Although the Taobao web interface is available in Chinese only, it works well when translated to English using Google Chrome and accepts payment via Mastercard, so I was able to make the purchase with no issues.

The card arrived after 2 weeks, and looked like this:

CH375 ISA to USB with no bracket

In the above photo, the ISA bracket has been removed. It is however recommended that you always connect the ISA bracket, to prevent inserting the card in reverse (the ISA connector is just 8-bit and will fit in either way), which may destroy both the card and the motherboard.

First I want to say a few words on the CH375. It was originally released as a USB interface module specifically designed for mass storage devices such as USB thumb drives. There are several variants of the module available on eBay allowing interface via SPI or a proprietary serial protocol. As for the CH375 USB to ISA adapter, it is originally designed by lo-tech and makes uses of the CH375 chipset to allow connecting USB mass storage devices to machines with only 8-bit ISA slots.

Using USB flash drives under DOS

Although lo-tech’s design places the card’s IO port at addresses 2C0-2C8h with a 32KB BIOS at either C800h or D800h, my card’s default IO port is at address 260h instead, configurable via jumpers. Getting the card works in DOS simply involves connecting a USB flash drive containing a single FAT16 partition that is 512MB or less in size, and followed by adding these lines to CONFIG.SYS:

DEVICE=C:\CH375\CH375DOS.SYS @260 #07

where 260 is the address of the card and 07 is the software interrupt for the card. You should select an available interrupt, otherwise there will be weird issues when reading/writing to the card. If you are using the PCI version of the card, pass 0 as the address. The driver also accepts a third optional parameter that can be anything between 0 to 255, specifying the read/write speed. The higher the value, the faster the speed. Default value is 2.

With the above configuration, I was able to create a new DOS drive letter for my USB thumb drive and access it with no issues. The throughput is around 8KB/s on a PC XT running at 12MHz. I guess the speed should be much higher on 386 and 486 machines.

Take note that loading CH375DOS.SYS will freeze the system if the USB drive is larger than 512MB, not formatted as FAT16, or contains multiple partitions. Also, only USB thumb drives are expected to work. USB hard disks will most likely not work as intended, unless used with an external power supply.

Configuring BIOS boot ROM

There is a socket on the card for a 27C64 EPROM for booting. 28C64 ROMs might work too, but I haven’t had the time to try yet. Finding the right boot ROM might also be an issue. There are at least a few versions of the ROM available for download at various sites, none of them seem to work out of the box:

  1. ROM v1.3 from lo-tech. This ROM simply prints “Start CH375 v1.3 …” in an infinite loop after POST, followed by repeated beeps, and you’ll have to reset the machine.
  2. ROM v1.5 with Ctrl prompt. This ROM adds a message “Press Ctrl to start E-Disk” during POST. The window for pressing Ctrl is less than 1 second. Pressing too early and it would cause the BIOS to report keyboard error. Pressing it late and your machine would have already booted normally. I could not get this ROM to work.
  3. ROM v1.5 (modified) without Ctrl prompt but hard-coded strange disk geometry taken from this discussion thread. This ROM removes the Ctrl prompt and attempts to boot directly from USB but assumes a disk geometry of 0x20 sectors per track and 0x40 heads, which would not work with most thumb drives.

I decided to start my analysis from version (3) of the ROM, using IDA Pro and information from the above discussion thread, together with my Minipro USB programmer. If you want to try, the first thing to do is learning how to properly prepare the ROM file. For the CH375, the board accepts a ROM size of 8KB, but various downloads only provide ROM sizes of 2KB or 4KB. If that is the case, use a hex editor and append zero to the end of the file until the size is exactly 8192 bytes before programming. There might also be another issue with the ROM checksum, which is the last byte of the ROM calculated by taking the byte value of last 8 bits of the sum of all bytes in the ROM (including the checksum bytes). Depending on the firmware of your ISA to USB card, the card will either recognize the ROM as long as the checksum matches, or will recognize the ROM only if this checksum byte is zero. To cater for this, if the ROM you attempt to flash does not have zero as the last byte, you will need to modify existing bytes to get a checksum of 0. This can be done by modifying the padded zero bytes, or one of the displayed ASCII characters.

The next thing to do is patching the BIOS to reflect the correct address for the CH375. On v1.3 of the BIOS, this address is located at 0x38 – 0x39. However, on v1.5, the address is located at 0x36 – 0x37. The next byte is the address of the emulated hard disk which defaults to 80h for the primary master channel.  A pair of 2 bytes (3F FF) on the right provides the hard-coded geometry of the USB drive:


In the above screenshot, the card is located at 260h and the BIOS assumes a USB drive having 63 sectors per track and 255 heads (approximately 528MB), the usual limitation for older BIOSes. With this settings, any modern USB drive should work, albeit at a much smaller capacity. You can download a ZIP file with CH375DOS.SYS and the patched 8KB ROM file here.

There is still a step that needs to be done before you can use your USB thumbrive with this BIOS. Even though the CH375 recognizes the USB thumb drive, you must first get your DOS system files on it first before the machine can boot. And you can’t do that from a DOS boot disk, nor from Windows, due to the need to have the BIOS loaded first and the hard coded disk geometry. The only way I could get it to work is to create a DOS virtual machine in VirtualBox with a hard disk containing a single active partition of 500MB, then follow this tutorial to convert the disk image to DD format, and finally use Rufus to write the DD image to the thumb drive. Once then, my XT machine could boot using the thumb drive connected to the CH375 to USB adapter.

You can see in the following video my 80286 running at 12.5MHz booting from a USB thumb drive via the CH375 adapter. Disk throughput when using the CH375 BIOS is around 12KB/s:

Disassembling the BIOS source code

There are still a few issues with this BIOS. First, I think the code is not optimized and the throughput can be faster. Secondly, FDISK and several other disk utilities do not detect a fixed disk when using this BIOS. As a result, formatting the disk is impossible and I have to resort to using the above DD method. Also, this BIOS does not provide a way to boot from floppy disks, so I had to resort to using System Commander for floppy disk boot selection, resulting in the lengthy boot delay.

You can download here the IDA project which I used to study this BIOS. The link also contains a partial disassembly of the BIOS code. I have also given all identified functions sensible names, renamed several labels, and added comments to illustrate the communication protocol with the CH375 module:


I started off by using IDA to disassemble the BIOS as 16-bit 8086 code and relying on IDA comments, auto-comments, list of text strings as well as the datasheet to identify various code segments. Most notably, there is a function which I named CHS2LBA in the code, responsible for converting the assumed geometry of the thumb drive to LBA sectors to be passed to the CH375 module:

seg000:0372 CHS2LBA proc near ; CODE XREF: seg000:067Ap
seg000:0372 mov al, cs:CHS_SECTORS
seg000:0376 mul dh ; Unsigned Multiplication of AL or AX
seg000:0378 mov dl, ch
seg000:037A mov dh, cl
seg000:037C and cx, 3Fh ; Logical AND
seg000:037F dec cx ; Decrement by 1
seg000:0380 add cx, ax ; Add
seg000:0382 shr dh, 1 ; Shift Logical Right
seg000:0384 shr dh, 1 ; Shift Logical Right
seg000:0386 shr dh, 1 ; Shift Logical Right
seg000:0388 shr dh, 1 ; Shift Logical Right
seg000:038A shr dh, 1 ; Shift Logical Right
seg000:038C shr dh, 1 ; Shift Logical Right
seg000:038E mov al, cs:CHS_SECTORS
seg000:0392 mov ah, 0
seg000:0394 mul dx ; Unsigned Multiplication of AL or AX
seg000:0396 mov dl, cs:CHS_HEAD
seg000:039B mul dx ; Unsigned Multiplication of AL or AX
seg000:039D add ax, cx ; Add
seg000:039F adc dx, 0 ; Add with Carry
seg000:03A2 retn ; Return Near from Procedure
seg000:03A2 CHS2LBA endp

As can be seen, there are several bit shifts in this function. I leave it as an exercise for the reader to find out what this function is exactly doing, and perhaps write its C equivalent. It is also worth noting that IDA fails to identify several pieces of code for interrupt 13H and did not disassemble them but instead identify those as data. I saw several of these in IDA Pro and renamed them properly:


To force IDA to disassemble these functions, select the area which you think has been misidentified as data, right click and select Code. You should see the INT 13H function being disassembled nicely:

NEW_INT13H: ;New interrupt 13H to replace BIOS INT 13H to emulate USB hard drive
seg000:0519 cmp dl, cs:HDD_DISK_NUM ; Compare Two Operands
seg000:051E jnz short NEW_INT13H_GO0 ; Jump if Not Zero (ZF=0)
seg000:0520 cmp ah, 2 ; AH=2, Read Sector
seg000:0523 jz short NEW_INT13H_RD9 ; Jump if Zero (ZF=1)
seg000:0525 cmp ah, 3 ; AH=3,Write Sector
seg000:0528 jz short NEW_INT13H_WR9 ; Jump if Zero (ZF=1)
seg000:052A cmp ah, 4 ; AH=4,Verify Sector
seg000:052D jz short NEW_INT13H_SVC ; Jump if Zero (ZF=1)
seg000:052F cmp ah, 8 ; AH=8, Read Drive Parameter
seg000:0532 jz short NEW_INT13H_08H ; Jump if Zero (ZF=1)
seg000:0534 cmp ah, 1 ; AH=1, Get Last Operation Status
seg000:0537 jbe short NEW_INT13H_SVC ; Jump if Below or Equal (CF=1 | ZF=1)
seg000:0539 cmp ah, 40h ; '@' ; Compare Two Operands
seg000:053C jb short NEW_INT13H_GO ; Jump if Below (CF=1)
seg000:053E cmp ah, 41h ; 'A' ; AH=41H, Check Extension Present
seg000:0541 jz short NEW_INT13H_SVC0 ; Jump if Zero (ZF=1)
seg000:0543 cmp ah, 42h ; 'B' ; AH=42H, Extended Read Sectors
seg000:0546 jz short NEW_INT13H_RDX1 ; Jump if Zero (ZF=1)
seg000:0548 cmp ah, 43h ; 'C' ; AH=43H, Extended Write Sectors
seg000:054B jz short NEW_INT13H_WRX1 ; Jump if Zero (ZF=1)
seg000:054D cmp ah, 44h ; 'D' ; AH=44H, Verify Sectors
seg000:0550 jz short NEW_INT13H_SVC ; Jump if Zero (ZF=1)
seg000:0552 cmp ax, 572Ah ; Compare Two Operands
seg000:0555 jz short NEW_INT13H_ID ; Jump if Zero (ZF=1)
seg000:0557 mov ah, 1
seg000:0559 stc ; Set Carry Flag
seg000:055A jmp short NEW_INT13H_RET ; Jump

One last thing that I want to mention is that, this BIOS ROM does not map itself into the 8086 memory address space. Therefore it is not possible to dump the ROM contents from software, for example, by using DEBUG.EXE or any ROM dump utility.

Download the entire set of files that I have for the CH375 here. The ZIP file contains complete documentation (circuit schematics, datasheet) for the CH375 and similar modules, PCB/PLD designs, DOS tools, BIOS collections, as well as sample application. Some of the README.TXT files were originally in Chinese but have been translated by me to English using Google Translate – these files are given an .ENG extension.  I hope these files will be useful for those who want to explore the adapter more and perhaps write a better BIOS for it. :)

See also

The good old days: cracking 16-bit DOS games

5.00 avg. rating (93% score) - 1 vote


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>