From cf2abc64b00509d5344ca540a17f2d37109dbdee Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Wed, 22 Jul 2026 05:25:59 +0900 Subject: [PATCH] ided: implement PCI native mode for primary and secondary IDE channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI IDE Programming Interface byte (PCI spec §3.1.1) encodes per-channel mode: bit 0 = primary native, bit 2 = secondary native. The previous code panicked on native-mode channels and also had a bug checking bit 0 for both channels (secondary should check bit 2). Native mode now reads I/O and control bases from PCI BARs (BAR0/1 for primary, BAR2/3 for secondary) instead of hardcoded legacy ports. Interrupt line comes from legacy_interrupt_line when available. --- drivers/storage/ided/src/main.rs | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/storage/ided/src/main.rs b/drivers/storage/ided/src/main.rs index 4632316a0b..10dbbcb0a5 100644 --- a/drivers/storage/ided/src/main.rs +++ b/drivers/storage/ided/src/main.rs @@ -44,13 +44,45 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { let dma = pci_config.func.full_device_id.interface & 0x80 != 0; let busmaster_base = pci_config.func.bars[4].expect_port(); - let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { - panic!("TODO: IDE primary channel is PCI native"); + + // PCI IDE Programming Interface byte (PCI spec §3.1.1): + // bit 0: primary channel operates in native mode (else compatibility) + // bit 1: primary channel is switchable + // bit 2: secondary channel operates in native mode (else compatibility) + // bit 3: secondary channel is switchable + // + // In compatibility mode, the legacy I/O ports (0x1F0/0x3F6 primary, + // 0x170/0x376 secondary) and IRQs (14/15) are hardwired. In native mode, + // the I/O base and control base come from PCI BARs and the interrupt + // comes from the PCI interrupt pin (INTA#/INTB#). + let interface = pci_config.func.full_device_id.interface; + + let (primary, primary_irq) = if interface & 0x01 != 0 { + // Primary native: BAR0 = I/O base, BAR1 = control base + let io_base = pci_config.func.bars[0].expect_port(); + let ctrl_base = pci_config.func.bars[1].expect_port(); + let irq = pci_config + .func + .legacy_interrupt_line + .map(|l| l.irq) + .unwrap_or(14); + info!("IDE primary channel: native mode io={:#x} ctrl={:#x} irq={}", io_base, ctrl_base, irq); + (Channel::new(io_base, ctrl_base, busmaster_base).unwrap(), irq) } else { (Channel::primary_compat(busmaster_base).unwrap(), 14) }; - let (secondary, secondary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { - panic!("TODO: IDE secondary channel is PCI native"); + + let (secondary, secondary_irq) = if interface & 0x04 != 0 { + // Secondary native: BAR2 = I/O base, BAR3 = control base + let io_base = pci_config.func.bars[2].expect_port(); + let ctrl_base = pci_config.func.bars[3].expect_port(); + let irq = pci_config + .func + .legacy_interrupt_line + .map(|l| l.irq) + .unwrap_or(15); + info!("IDE secondary channel: native mode io={:#x} ctrl={:#x} irq={}", io_base, ctrl_base, irq); + (Channel::new(io_base, ctrl_base, busmaster_base + 8).unwrap(), irq) } else { (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) };