ISA Plug and Play Isolation from DOS: Serial IDs, READ_DATA, and CSNs
Trace ISA Plug and Play card isolation from real-mode DOS, validate the serial identifier and checksum, and avoid changing live device resources.
ISA Plug and Play (PnP) is a hardware configuration protocol, not a DOS driver and not the Plug and Play BIOS API. A real-mode DOS utility can use the ISA protocol to identify compatible cards by their serial identifiers, but the procedure uses writes to shared configuration ports and changes each card’s protocol state. It is not a passive, read-only probe. Do not run an experimental enumerator while a sound, network, storage, or other ISA driver is using the same cards.
This guide covers the ISA bus isolation stage: selecting a read-data port, distinguishing multiple cards, validating each identifier, and assigning card-select numbers (CSNs). It deliberately does not program logical-device I/O ranges, IRQs, DMA channels, or activation registers. Those are a separate resource-allocation task and can make a machine unbootable or leave a DOS driver talking to the wrong hardware.
Keep ISA PnP separate from BIOS and PCI discovery
The ISA PnP specification defines card-side configuration registers and an electrical serial-isolation protocol over the ISA I/O bus. The PnP BIOS specification instead defines firmware entry points and system-device nodes. PCI BIOS enumeration uses a third interface. A BIOS may configure ISA PnP cards during startup, but reading a PnP BIOS node is not the same operation as restarting the ISA card-isolation algorithm. Likewise, finding a PCI device through INT 1Ah does not enumerate an ISA PnP card.
The original ISA PnP 1.0a specification was published by Intel and Microsoft on May 5, 1994. Its port sequence and state machine are the normative reference for the protocol described here. Linux’s upstream ISA PnP core is useful as a second, implementation-level reference; its timing and candidate-port policies are implementation choices, not extra requirements imposed on every DOS program.
Three ports, with one address chosen at runtime
The protocol exposes three 8-bit I/O ports. ADDRESS is write-only at 0279h; WRITE_DATA is write-only at 0A79h; and READ_DATA is read-only at a relocatable address from 0203h through 03FFh. Software first writes a PnP register number to ADDRESS, then transfers its value through the selected data port. The READ_DATA location is selected by a PnP register command during isolation, because a fixed read port could collide with another ISA device.
The chosen read address is encoded in the Set Read Data Port register: data bits 7:0 become ISA address bits 9:2, while address bits 1:0 are fixed to binary 11 and bits 15:10 to zero. Thus an address such as 0213h is represented by 0213h >> 2, not by writing the full port number. The Linux implementation uses that same right shift when setting the register. This arithmetic is easy to get wrong in a test harness, so log both the requested port and the byte written.
Before the register protocol is active, software must send the 32-byte Initiation Key to the ADDRESS port. The key is the sequence generated by the specification’s 8-bit LFSR, initialized to 6Ah; two 00h writes reset its recognizer before the key is sent. After the key, software wakes cards with CSN zero into the Isolation state, selects the read-data port, and only then starts the serial reads. A reset-related delay is also part of the specification’s flow: allow the documented settling interval after reset commands instead of treating the ports as immediately ready.
How two reads separate cards sharing one bus
Each card presents a 72-bit serial identifier: a 32-bit vendor/product identifier, a 32-bit unique number, and an 8-bit checksum. The specification requires the combined 64-bit vendor-and-serial value to be unique within one system; duplicate identities violate the algorithm’s assumption and cannot safely be treated as two independently addressable cards. Identifier bits are shifted least-significant bit first within each byte. For each identifier bit, software performs a pair of reads from the Serial Isolation register at the selected READ_DATA port.
If a card’s current identifier bit is one, it drives 55h during the first read cycle and AAh during the second. A card whose bit is zero leaves the bus in high impedance and observes whether another card drove the expected pattern; if no card drives that pattern, the pair is read as a zero bit. Thus, a single pair without the 55h/AAh pattern is normal and does not by itself indicate a port conflict. Cards that lose the wired isolation comparison stop participating in that pass. After all 72 bit pairs, one card remains isolated; the software checks its checksum, assigns it a nonzero CSN, and repeats to isolate another card. The CSN is a selector for later card commands, not the card’s vendor ID or a permanent serial number. The specification defines valid assigned CSNs as 1 through 255, sequentially allocated.
This Wake[0] loop enumerates only cards whose CSN is already zero. If firmware has assigned nonzero CSNs and returned those cards to Wait for Key, this pass does not rediscover them. A utility must not label a CSN-zero isolation pass as a complete inventory of every card on the bus.
The software’s checksum is important. It reads each pair with the 55h/AAh combination as a one bit and all other pairs as zero; individual nonmatching pairs are expected for zero bits. The conflict check applies to the whole isolation iteration: if no 55h/AAh pair is detected anywhere in the first 72-pair scan, or the computed checksum does not match the checksum bits read back, the specification treats the READ_DATA port as conflicting and calls for relocation. After a card has already been isolated, either condition means no further card was found and the enumeration pass is complete. Do not report “no cards present” after one failed port attempt without distinguishing that case from an actual empty bus.
At a high level, the state machine is:
enter configuration mode with the Initiation Key
wake unassigned cards (CSN 0) into Isolation
choose and set an available READ_DATA port
repeat:
read 72 serial-bit pairs and validate the 8-bit checksum
if a card wins:
assign the next CSN; return to isolating remaining CSN-0 cards
else if this was the first pass:
select another permitted READ_DATA port and retry
else:
stop: no further card was isolated
return cards to the documented Wait-for-Key state
This is protocol pseudocode, not a drop-in .COM routine. A real implementation must get the initiation-key LFSR, register selection, I/O timing, checksum bit order, and state transitions exactly right. The specification requires a delay before the first isolation pair and between subsequent pairs; Linux’s upstream implementation also shows explicit microsecond delays around I/O. Do not optimize those waits away because a fast emulator happened to pass one test.
Discovery does not allocate resources or load a driver
After isolation, a card can enter the Config state and expose its resource data, but the returned alternatives are descriptions, not reservations. A card may contain several logical devices, each with possible I/O, IRQ, DMA, or memory ranges. An enumerator that only assigns CSNs has not selected a conflict-free configuration and has not activated a logical device. Conversely, writing resource registers or setting an Activate bit changes the hardware configuration; do not add those writes to an inventory tool without a separate allocator, conflict check, driver handoff plan, and rollback method.
The end state matters. The specification says the normal operating state is Wait for Key and directs configuration software to return cards there after configuration. Its Wait-for-Key command preserves existing CSNs and logical-device status. Reset-CSN is a separate command that sets CSNs to zero only when cards are not in Wait for Key; after it, READ_DATA is uninitialized and must be set again before isolation. The Reset command instead restores logical-device configuration registers to their defaults while preserving CSNs and READ_DATA. Treat either as an intentional configuration-state change, not casual cleanup; if a tool cannot establish the machine’s intended state and recovery path, limit it to an isolated test system.
A controlled DOS validation plan
Begin on a disposable machine or a VM whose documentation explicitly confirms ISA PnP card emulation. Keep the original boot profile and device configuration. Test one known card first, then add a second card only after the first card’s identifier and checksum are stable. Record the machine or emulator, card model, BIOS behavior, selected read-data port, raw returned bytes, computed checksum, assigned CSNs, and whether each result survives a cold boot. Do not infer hardware compatibility from a successful run in an emulator that merely supports generic ISA devices.
Use a test matrix that includes: no ISA PnP card; one card; multiple cards; a deliberately unusable candidate read port; a malformed or checksum-failing trace in a simulator; and a repeat run after the documented state transition. A no-card system should terminate cleanly without unbounded port scans. A conflict should cause a bounded port change, not an endless retry. Keep the trace separate from resource descriptors so an invalid identifier cannot be mistaken for a valid device record.
If you need supported devices rather than a protocol exercise, prefer the platform’s tested BIOS configuration and vendor-supplied DOS drivers. If the aim is inventory, label results as “ISA PnP serial identifier observed,” not “device configured” or “driver available.” If the aim is to change resources, stop and use a complete ISA PnP configuration utility whose allocation rules and restoration behavior are documented for the exact machine.
ISA PnP isolation is a compact example of distributed hardware discovery: several cards answer together, and the bus-level comparison progressively identifies one responder at a time. The protocol is valuable for understanding and preserving legacy systems, but its configuration ports are shared state. A careful DOS tool validates the full serial identifier, treats conflicts as first-class results, and never confuses identifying a card with safely configuring it.
Related:
- Reading Legacy PnP BIOS Device Nodes from a DOS Utility
- Enumerating PCI Devices from Real-Mode DOS with the PCI BIOS
Sources:
- The ISA PnP 1.0a PDF below is mirrored by ETHW/IEEE Milestones, not hosted by Intel or Microsoft. The Linux links are pinned implementation corroboration; the specification remains the protocol authority.
- Plug and Play ISA Specification, version 1.0a (Intel and Microsoft, May 5, 1994)
- Linux upstream ISA PnP implementation, pinned revision: isolation, checksum, read-port selection, and CSN assignment
- Linux upstream ISA PnP implementation, pinned revision: ADDRESS and WRITE_DATA port constants
- Linux upstream ISA PnP implementation, pinned revision: READ_DATA register encoding