ided: implement PCI native mode for primary and secondary IDE channels

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.
This commit is contained in:
Red Bear OS
2026-07-22 05:25:59 +09:00
parent 6571df7802
commit cf2abc64b0
+36 -4
View File
@@ -44,13 +44,45 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
let dma = pci_config.func.full_device_id.interface & 0x80 != 0; let dma = pci_config.func.full_device_id.interface & 0x80 != 0;
let busmaster_base = pci_config.func.bars[4].expect_port(); 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 { } else {
(Channel::primary_compat(busmaster_base).unwrap(), 14) (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 { } else {
(Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15)
}; };