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