kernel/ATA: Start reading/writing registers and detecting drives

This commit is contained in:
apio 2023-05-13 14:11:09 +02:00
parent e8507d23ee
commit 3a84127fd6
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 118 additions and 16 deletions

View File

@ -45,30 +45,88 @@ namespace ATA
{
}
u8 Channel::read_register(Register reg)
{
return IO::inb(m_io_base + (u16)reg);
}
void Channel::write_register(Register reg, u8 value)
{
IO::outb(m_io_base + (u16)reg, value);
}
u8 Channel::read_control(ControlRegister reg)
{
return IO::inb(m_control_base + (u16)reg);
}
void Channel::write_control(ControlRegister reg, u8 value)
{
IO::outb(m_control_base + (u16)reg, value);
}
void Channel::delay_400ns()
{
read_control(ControlRegister::AltStatus);
read_control(ControlRegister::AltStatus);
read_control(ControlRegister::AltStatus);
read_control(ControlRegister::AltStatus);
}
void Channel::select(u8 drive)
{
if (drive == m_current_drive) return;
u8 value = (drive << 4) | 0xa0;
write_register(Register::DriveSelect, value);
delay_400ns();
m_current_drive = drive;
}
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 ");
u32 control_port_base_address;
u32 io_base_address;
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 =
// FIXME: Properly decode BARs.
io_base_address = PCI::read32(m_controller->device().address, m_channel_index ? PCI::BAR2 : PCI::BAR0);
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;
io_base_address = m_channel_index ? 0x170 : 0x1f0;
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;
m_io_base = (u16)io_base_address;
m_control_base = (u16)control_port_base_address + 2;
kinfoln("ata: Channel %d uses IRQ %hhu", m_channel_index, interrupt_line);
if (m_is_pci_native_mode) m_interrupt_line = PCI::read8(m_controller->device().address, PCI::InterruptLine);
else
m_interrupt_line = m_channel_index ? 15 : 14;
for (u8 drive = 0; drive < 2; drive++)
{
ScopedKMutexLock<100> lock(m_lock);
select(drive);
if (read_register(Register::Status) == 0)
{
// No drive on this slot.
continue;
}
kinfoln("ata: Channel %d has a drive on slot %d!", m_channel_index, drive);
}
return true;
}

View File

@ -7,12 +7,53 @@
namespace ATA
{
enum class Register : u16
{
Data = 0,
Error = 1,
Features = 1,
SectorCount = 2,
SectorNumber = 3,
LBALow = 3,
CylinderLow = 4,
LBAMiddle = 4,
CylinderHigh = 5,
LBAHigh = 5,
DriveSelect = 6,
Status = 7,
Command = 8,
};
enum class ControlRegister : u16
{
AltStatus = 0,
DeviceControl = 0,
DriveAddress = 1,
};
class Controller;
class Channel;
class Drive
{
private:
Channel* m_channel;
};
class Channel
{
public:
Channel(Controller* controller, u8 channel_index, Badge<Controller>);
u8 read_register(Register reg);
void write_register(Register reg, u8 value);
u8 read_control(ControlRegister reg);
void write_control(ControlRegister reg, u8 value);
void delay_400ns();
void select(u8 drive);
bool initialize();
private:
@ -20,8 +61,14 @@ namespace ATA
u8 m_channel_index;
bool m_is_pci_native_mode;
u32 m_base_address;
u32 m_control_port_base_address;
u8 m_interrupt_line;
KMutex<100> m_lock {};
u16 m_io_base;
u16 m_control_base;
u8 m_current_drive = (u8)-1;
};
class Controller
@ -41,8 +88,6 @@ namespace ATA
PCI::Device m_device;
Channel m_primary_channel;
Channel m_secondary_channel;
KMutex<100> m_lock;
};
}

View File

@ -52,9 +52,8 @@ template <usize ConcurrentThreads> class KMutex
template <usize ConcurrentThreads> class ScopedKMutexLock
{
public:
ScopedKMutexLock(KMutex<ConcurrentThreads>& lock)
ScopedKMutexLock(KMutex<ConcurrentThreads>& lock) : m_lock(lock)
{
m_lock = lock;
m_lock.lock();
}