How Windows 95 Handled PCI IRQ Sharing

Before the Advanced Configuration and Power Interface (ACPI) standardized hardware configuration, managing hardware interrupts on the PC platform was a delicate balance between modern PCI hardware and legacy ISA architecture. Windows 95 navigated this transition by relying heavily on system BIOS tables, level-triggered interrupt mechanics, and the eventual introduction of PCI IRQ Steering in later updates to map multiple PCI devices to a scarce pool of legacy interrupt lines.

The Conflict: Edge-Triggered vs. Level-Triggered Interrupts

The primary challenge in pre-ACPI interrupt management stemmed from the system architecture of the era. The standard PC platform still relied on the dual Intel 8259 Programmable Interrupt Controller (PIC) design, which provided only 15 usable Interrupt Request (IRQ) lines. Legacy ISA cards used edge-triggered interrupts, meaning an interrupt was signaled by a voltage transition; if two ISA devices shared an IRQ, the system could easily miss an interrupt edge, leading to system lockups.

In contrast, the PCI specification was designed specifically to support interrupt sharing using level-triggered interrupts across four physical lines: INTA#, INTB#, INTC#, and INTD#. With level-triggered signaling, an asserting device holds the line at a specific voltage until serviced. While this design inherently allowed multiple devices to pull down the same line safely, these signals still had to be translated into the legacy 8259 PIC's ISA IRQ space for the operating system to process them.

Initial Windows 95 Releases and BIOS Mapping

In the original release of Windows 95 (Retail/Gold), the operating system lacked internal logic to dynamically re-route or steer PCI interrupts. Instead, it relied entirely on the motherboard BIOS:

  1. Physical Swizzling: Motherboard traces were routed to offset ("swizzle") the INTx pins across different physical slots, spreading interrupt requests naturally across the system's interrupt router chipset.
  2. Static BIOS Assignment: During the Power-On Self-Test (POST), the BIOS queried the devices on the PCI bus and assigned each active INTx line an available ISA IRQ (commonly IRQ 9, 10, or 11).
  3. OS Passivity: Windows 95 simply accepted the IRQ assignments passed to it by the BIOS via the Plug and Play (PnP) interface. If the BIOS assigned two PCI devices to the same IRQ, Windows 95 accepted the configuration only if the motherboard chipset and the respective device drivers supported it. If the BIOS failed to configure the interrupt router properly, devices would experience severe hardware conflicts.

The Introduction of PCI IRQ Steering

To fix device conflicts and the exhaustion of IRQ lines caused by an increasing number of PCI add-in cards, Microsoft introduced PCI Bus IRQ Steering in Windows 95 OEM Service Release 2 (OSR2).

PCI IRQ Steering moved the dynamic assignment of interrupts from the BIOS to the operating system:

  • The $PIR Table: Windows 95 OSR2 searched system memory for the PCI IRQ Routing Table (indicated by the $PIR signature). Built by the motherboard BIOS, this table provided a physical roadmap of which PCI slots and INTx pins were wired to which inputs on the motherboard's interrupt router (the programmable chipset component connecting PCI lines to the 8259 PIC).
  • Dynamic Programming: With the $PIR table loaded, Windows 95's PCI bus driver could program the motherboard's chipset directly to map multiple PCI devices to a single legacy IRQ without BIOS intervention.
  • Resolution of Resource Conflicts: If an ISA device claimed a specific IRQ line, the operating system could dynamically reroute PCI devices to a different, shared IRQ, reserving exclusive lines for unshareable legacy hardware.

Interrupt Service Routine (ISR) Handling

Once an IRQ was shared under Windows 95, the operating system utilized a "daisy-chain" software method to handle incoming interrupts:

  1. When a PCI interrupt fired, the 8259 PIC flagged the assigned IRQ to the CPU.
  2. Windows 95 invoked the Interrupt Service Routine (ISR) for the first device registered to that IRQ.
  3. The driver checked its hardware's status register to see if it generated the interrupt. If it did, it serviced the request and cleared the interrupt state.
  4. If the device did not generate the interrupt, the driver returned control to Windows, which immediately called the ISR for the next device sharing the line.
  5. This process repeated down the chain until the asserting device was found and the level-triggered line returned to its idle state.

This combination of BIOS-provided $PIR tables, chipset programming via PCI IRQ Steering, and chained driver interrupt routines allowed Windows 95 to effectively handle multi-device PCI configurations long before ACPI and APIC architectures expanded the physical number of available system interrupts.