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:
@@ -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)
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user