Kernel: Rework interrupt mechanism

All interruptrable classes now inherit from Interruptable which
has methdo handle_irq which is called on a interrupt.
This commit is contained in:
2023-10-05 18:53:45 +03:00
parent 68a913c838
commit 27eb5af6f0
23 changed files with 716 additions and 706 deletions

View File

@@ -2,6 +2,7 @@
#include <kernel/ACPI.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IDT.h>
#include <kernel/Input/PS2Config.h>
#include <kernel/Input/PS2Controller.h>
#include <kernel/Input/PS2Keyboard.h>
#include <kernel/InterruptController.h>
@@ -11,77 +12,6 @@
namespace Kernel::Input
{
namespace PS2
{
enum IOPort : uint8_t
{
DATA = 0x60,
STATUS = 0x64,
COMMAND = 0x64,
};
enum Status : uint8_t
{
OUTPUT_FULL = (1 << 0),
INPUT_FULL = (1 << 1),
SYSTEM = (1 << 2),
DEVICE_OR_CONTROLLER = (1 << 3),
TIMEOUT_ERROR = (1 << 6),
PARITY_ERROR = (1 << 7),
};
enum Config : uint8_t
{
INTERRUPT_FIRST_PORT = (1 << 0),
INTERRUPT_SECOND_PORT = (1 << 1),
SYSTEM_FLAG = (1 << 2),
ZERO1 = (1 << 3),
CLOCK_FIRST_PORT = (1 << 4),
CLOCK_SECOND_PORT = (1 << 5),
TRANSLATION_FIRST_PORT = (1 << 6),
ZERO2 = (1 << 7),
};
enum Command : uint8_t
{
READ_CONFIG = 0x20,
WRITE_CONFIG = 0x60,
DISABLE_SECOND_PORT = 0xA7,
ENABLE_SECOND_PORT = 0xA8,
TEST_SECOND_PORT = 0xA9,
TEST_CONTROLLER = 0xAA,
TEST_FIRST_PORT = 0xAB,
DISABLE_FIRST_PORT = 0xAD,
ENABLE_FIRST_PORT = 0xAE,
WRITE_TO_SECOND_PORT = 0xD4,
};
enum Response
{
TEST_FIRST_PORT_PASS = 0x00,
TEST_SECOND_PORT_PASS = 0x00,
TEST_CONTROLLER_PASS = 0x55,
SELF_TEST_PASS = 0xAA,
ACK = 0xFA,
};
enum DeviceCommand
{
ENABLE_SCANNING = 0xF4,
DISABLE_SCANNING = 0xF5,
IDENTIFY = 0xF2,
RESET = 0xFF,
};
enum IRQ
{
DEVICE0 = 1,
DEVICE1 = 12,
};
}
static constexpr uint64_t s_device_timeout_ms = 100;
static void controller_send_command(PS2::Command command)
@@ -136,20 +66,6 @@ namespace Kernel::Input
return {};
}
void PS2Controller::device0_irq()
{
auto& controller = PS2Controller::get();
ASSERT(controller.m_devices[0] != nullptr);
controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA));
}
void PS2Controller::device1_irq()
{
auto& controller = PS2Controller::get();
ASSERT(controller.m_devices[1] != nullptr);
controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA));
}
static PS2Controller* s_instance = nullptr;
BAN::ErrorOr<void> PS2Controller::initialize()
@@ -256,15 +172,15 @@ namespace Kernel::Input
if (m_devices[0])
{
IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq);
InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
m_devices[0]->enable_interrupt();
config |= PS2::Config::INTERRUPT_FIRST_PORT;
DevFileSystem::get().add_device("input0", m_devices[0]);
}
if (m_devices[1])
{
IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq);
InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
m_devices[1]->set_irq(PS2::IRQ::DEVICE1);
m_devices[1]->enable_interrupt();
config |= PS2::Config::INTERRUPT_SECOND_PORT;
DevFileSystem::get().add_device("input1", m_devices[1]);
}

View File

@@ -1,7 +1,9 @@
#include <BAN/ScopeGuard.h>
#include <kernel/CriticalScope.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/PS2Config.h>
#include <kernel/Input/PS2Keyboard.h>
#include <kernel/IO.h>
#include <kernel/Timer/Timer.h>
#include <sys/sysmacros.h>
@@ -12,35 +14,6 @@
namespace Kernel::Input
{
namespace PS2
{
enum Response
{
KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00,
SELF_TEST_PASSED = 0xAA,
ECHO_RESPONSE = 0xEE,
ACK = 0xFA,
RESEND = 0xFE,
KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF,
};
enum Scancode
{
SET_SCANCODE_SET1 = 1,
SET_SCANCODE_SET2 = 2,
SET_SCANCODE_SET3 = 3,
};
enum Leds
{
SCROLL_LOCK = (1 << 0),
NUM_LOCK = (1 << 1),
CAPS_LOCK = (1 << 2),
};
}
BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller)
{
PS2Keyboard* keyboard = new PS2Keyboard(controller);
@@ -57,8 +30,10 @@ namespace Kernel::Input
, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
{ }
void PS2Keyboard::on_byte(uint8_t byte)
void PS2Keyboard::handle_irq()
{
uint8_t byte = IO::inb(PS2::IOPort::DATA);
// NOTE: This implementation does not allow using commands
// that respond with more bytes than ACK
switch (m_state)
@@ -71,11 +46,11 @@ namespace Kernel::Input
m_command_queue.pop();
m_state = State::Normal;
break;
case PS2::Response::RESEND:
case PS2::KBResponse::RESEND:
m_state = State::Normal;
break;
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1:
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2:
case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1:
case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2:
dwarnln("Key detection error or internal buffer overrun");
break;
default:
@@ -97,7 +72,7 @@ namespace Kernel::Input
BAN::ErrorOr<void> PS2Keyboard::initialize()
{
append_command_queue(Command::SET_LEDS, 0x00);
append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2);
append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2);
append_command_queue(Command::ENABLE_SCANNING);
return {};
}
@@ -234,11 +209,11 @@ namespace Kernel::Input
{
uint8_t new_leds = 0;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock)
new_leds |= PS2::Leds::SCROLL_LOCK;
new_leds |= PS2::KBLeds::SCROLL_LOCK;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock)
new_leds |= PS2::Leds::NUM_LOCK;
new_leds |= PS2::KBLeds::NUM_LOCK;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock)
new_leds |= PS2::Leds::CAPS_LOCK;
new_leds |= PS2::KBLeds::CAPS_LOCK;
append_command_queue(Command::SET_LEDS, new_leds);
}