#include "arch/x86_64/disk/ATA.h" #include "Log.h" #include "arch/x86_64/IO.h" #include SharedPtr g_controller; namespace ATA { Result Controller::scan() { // FIXME: Propagate errors. PCI::scan( [](const PCI::Device& device) { if (!g_controller) { auto controller = adopt_shared_if_nonnull(new (std::nothrow) Controller(device)).release_value(); kinfoln("ata: Found ATA controller on PCI bus (%x:%x:%x)", device.address.bus, device.address.function, device.address.slot); if (controller->initialize()) g_controller = controller; } }, { .klass = 1, .subclass = 1 }); return {}; } bool Controller::initialize() { if (!m_primary_channel.initialize()) return false; return m_secondary_channel.initialize(); } Controller::Controller(const PCI::Device& device) : m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {}) { } Channel::Channel(Controller* controller, u8 channel_index, Badge) : m_controller(controller), m_channel_index(channel_index) { } bool Channel::initialize() { int offset = m_channel_index ? 2 : 0; m_is_pci_native_mode = m_controller->device().type.prog_if & (1 << offset); kinfoln("ata: Channel %d is %sin PCI native mode", m_channel_index, m_is_pci_native_mode ? "" : "not "); if (m_is_pci_native_mode) { m_base_address = PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR2 : PCI::BAR0); m_control_port_base_address = PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR3 : PCI::BAR1); } else { m_base_address = m_channel_index ? 0x170 : 0x1f0; m_control_port_base_address = m_channel_index ? 0x376 : 0x3f6; } u8 interrupt_line; if (m_is_pci_native_mode) interrupt_line = PCI::read8(m_controller->device().address, PCI::InterruptLine); else interrupt_line = m_channel_index ? 15 : 14; kinfoln("ata: Channel %d uses IRQ %hhu", m_channel_index, interrupt_line); return true; } }