Add ATA drive support #27
@ -180,7 +180,7 @@ extern "C" void arch_interrupt_entry(Registers* regs)
|
||||
if (regs->isr < 32) handle_x86_exception(regs);
|
||||
else if (regs->isr >= 32 && regs->isr < 48) // IRQ from the PIC
|
||||
{
|
||||
u64 irq = regs->error;
|
||||
u64 irq = regs->irq;
|
||||
auto handler = irq_handlers[irq];
|
||||
if (!handler.function)
|
||||
{
|
||||
|
@ -5,7 +5,11 @@ struct Registers // Saved CPU registers for x86-64
|
||||
{
|
||||
u64 r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
u64 rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
u64 isr, error;
|
||||
u64 isr;
|
||||
union {
|
||||
u64 error;
|
||||
u64 irq;
|
||||
};
|
||||
u64 rip, cs, rflags, rsp, ss;
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@ SharedPtr<ATA::Controller> g_controller;
|
||||
|
||||
static void irq_handler(Registers* regs, void* ctx)
|
||||
{
|
||||
((ATA::Channel*)ctx)->irq_handler(regs);
|
||||
((ATA::Controller*)ctx)->irq_handler(regs);
|
||||
}
|
||||
|
||||
static usize copy_ata_string(char* out, u16* in, usize size)
|
||||
@ -70,6 +70,12 @@ namespace ATA
|
||||
return m_secondary_channel.initialize();
|
||||
}
|
||||
|
||||
void Controller::irq_handler(Registers* regs)
|
||||
{
|
||||
if (regs->irq == m_primary_channel.irq_line()) m_primary_channel.irq_handler(regs);
|
||||
if (regs->irq == m_secondary_channel.irq_line()) m_secondary_channel.irq_handler(regs);
|
||||
}
|
||||
|
||||
Controller::Controller(const PCI::Device& device)
|
||||
: m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {})
|
||||
{
|
||||
@ -150,7 +156,7 @@ namespace ATA
|
||||
|
||||
void Channel::irq_handler(Registers*)
|
||||
{
|
||||
// FIXME: Read the Busmaster register to make sure the IRQ is for this channel.
|
||||
if (!(read_bm(BusmasterRegister::Status) & BMS_IRQPending)) return;
|
||||
|
||||
if (m_current_drive < 2 && m_drives[m_current_drive]) m_drives[m_current_drive]->irq_handler();
|
||||
|
||||
@ -314,13 +320,7 @@ namespace ATA
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = CPU::register_interrupt(m_interrupt_line, ::irq_handler, this);
|
||||
if (!ok)
|
||||
{
|
||||
kerrorln("ata: Failed to register IRQ handler for ATA channel %d (IRQ %d)", m_channel_index,
|
||||
m_interrupt_line);
|
||||
return false;
|
||||
}
|
||||
CPU::register_interrupt(m_interrupt_line, ::irq_handler, m_controller);
|
||||
|
||||
for (u8 drive = 0; drive < 2; drive++)
|
||||
{
|
||||
|
@ -231,6 +231,11 @@ namespace ATA
|
||||
bool wait_for_irq_or_timeout(u64 timeout);
|
||||
void irq_handler(Registers*);
|
||||
|
||||
u8 irq_line()
|
||||
{
|
||||
return m_interrupt_line;
|
||||
}
|
||||
|
||||
void select(u8 drive);
|
||||
|
||||
bool initialize();
|
||||
@ -269,6 +274,8 @@ namespace ATA
|
||||
|
||||
bool initialize();
|
||||
|
||||
void irq_handler(Registers*);
|
||||
|
||||
private:
|
||||
Controller(const PCI::Device& device);
|
||||
PCI::Device m_device;
|
||||
|
@ -58,5 +58,5 @@ void pic_eoi(unsigned char irq)
|
||||
|
||||
void pic_eoi(Registers* regs)
|
||||
{
|
||||
pic_eoi((unsigned char)(regs->error)); // On IRQs, the error code is the IRQ number
|
||||
pic_eoi((unsigned char)(regs->irq));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user