forked from Bananymous/banan-os
Kernel: Move PS/2 command queue to controller instead of device
This commit is contained in:
parent
e8f853a197
commit
e4f48cbc73
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/Input/PS2/Config.h>
|
||||
|
@ -17,19 +18,17 @@ namespace Kernel::Input
|
|||
static BAN::ErrorOr<void> initialize();
|
||||
static PS2Controller& get();
|
||||
|
||||
BAN::ErrorOr<void> device_send_byte(PS2Device* device, uint8_t byte);
|
||||
|
||||
[[nodiscard]] bool lock_command(PS2Device*);
|
||||
void unlock_command(PS2Device*);
|
||||
bool append_command_queue(PS2Device*, uint8_t command, uint8_t response_size);
|
||||
bool append_command_queue(PS2Device*, uint8_t command, uint8_t data, uint8_t response_size);
|
||||
void update_command_queue();
|
||||
// Returns true, if byte is used as command, if returns false, byte is meant to device
|
||||
bool handle_command_byte(PS2Device*, uint8_t);
|
||||
|
||||
private:
|
||||
PS2Controller() = default;
|
||||
BAN::ErrorOr<void> initialize_impl();
|
||||
BAN::ErrorOr<void> initialize_device(uint8_t);
|
||||
|
||||
BAN::ErrorOr<void> reset_device(uint8_t);
|
||||
BAN::ErrorOr<void> set_scanning(uint8_t, bool);
|
||||
|
||||
BAN::ErrorOr<uint8_t> read_byte();
|
||||
BAN::ErrorOr<void> send_byte(uint16_t port, uint8_t byte);
|
||||
|
||||
|
@ -37,14 +36,31 @@ namespace Kernel::Input
|
|||
BAN::ErrorOr<void> send_command(PS2::Command command, uint8_t data);
|
||||
|
||||
BAN::ErrorOr<void> device_send_byte(uint8_t device_index, uint8_t byte);
|
||||
BAN::ErrorOr<void> device_read_ack(uint8_t device_index);
|
||||
BAN::ErrorOr<void> device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte);
|
||||
|
||||
private:
|
||||
struct Command
|
||||
{
|
||||
enum class State : uint8_t
|
||||
{
|
||||
NotSent,
|
||||
Sending,
|
||||
WaitingAck,
|
||||
WaitingResponse,
|
||||
};
|
||||
State state;
|
||||
uint8_t device_index;
|
||||
uint8_t out_data[2];
|
||||
uint8_t out_count;
|
||||
uint8_t in_count;
|
||||
uint8_t send_index;
|
||||
};
|
||||
|
||||
private:
|
||||
BAN::RefPtr<PS2Device> m_devices[2];
|
||||
RecursiveSpinLock m_lock;
|
||||
|
||||
PS2Device* m_executing_device { nullptr };
|
||||
PS2Device* m_pending_device { nullptr };
|
||||
BAN::CircularQueue<Command, 128> m_command_queue;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <kernel/Input/PS2/Controller.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
|
||||
|
@ -20,39 +19,16 @@ namespace Kernel::Input
|
|||
virtual void handle_irq() final override;
|
||||
|
||||
virtual void handle_byte(uint8_t) = 0;
|
||||
virtual void handle_device_command_response(uint8_t) = 0;
|
||||
|
||||
virtual BAN::StringView name() const final override { return m_name; }
|
||||
virtual dev_t rdev() const final override { return m_rdev; }
|
||||
|
||||
private:
|
||||
void update_command();
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
Normal,
|
||||
WaitingAck,
|
||||
WaitingResponse,
|
||||
};
|
||||
|
||||
struct Command
|
||||
{
|
||||
uint8_t out_data[2];
|
||||
uint8_t out_count;
|
||||
uint8_t in_count;
|
||||
uint8_t send_index;
|
||||
};
|
||||
virtual void update() final override { m_controller.update_command_queue(); }
|
||||
|
||||
private:
|
||||
const BAN::String m_name;
|
||||
const dev_t m_rdev;
|
||||
|
||||
PS2Controller& m_controller;
|
||||
State m_state = State::Normal;
|
||||
BAN::CircularQueue<Command, 10> m_command_queue;
|
||||
|
||||
friend class PS2Controller;
|
||||
PS2Controller& m_controller;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace Kernel::Input
|
|||
virtual void send_initialize() override;
|
||||
|
||||
virtual void handle_byte(uint8_t) final override;
|
||||
virtual void handle_device_command_response(uint8_t) final override;
|
||||
|
||||
private:
|
||||
PS2Keyboard(PS2Controller& controller);
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace Kernel::Input
|
|||
virtual void send_initialize() override;
|
||||
|
||||
virtual void handle_byte(uint8_t) final override;
|
||||
virtual void handle_device_command_response(uint8_t) final override;
|
||||
|
||||
private:
|
||||
PS2Mouse(PS2Controller& controller);
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte)
|
||||
{
|
||||
ASSERT(interrupts_enabled());
|
||||
LockGuard _(m_lock);
|
||||
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
|
||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||
|
@ -35,6 +36,7 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<uint8_t> PS2Controller::read_byte()
|
||||
{
|
||||
ASSERT(interrupts_enabled());
|
||||
LockGuard _(m_lock);
|
||||
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
|
||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||
|
@ -61,31 +63,6 @@ namespace Kernel::Input
|
|||
return {};
|
||||
}
|
||||
|
||||
bool PS2Controller::lock_command(PS2Device* device)
|
||||
{
|
||||
if (m_executing_device && m_executing_device != device)
|
||||
{
|
||||
ASSERT(!m_pending_device || m_pending_device == device);
|
||||
m_pending_device = device;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_executing_device = device;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PS2Controller::unlock_command(PS2Device* device)
|
||||
{
|
||||
ASSERT(m_executing_device == device);
|
||||
m_executing_device = nullptr;
|
||||
if (m_pending_device)
|
||||
{
|
||||
m_executing_device = m_pending_device;
|
||||
m_pending_device = nullptr;
|
||||
m_executing_device->update_command();
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::device_send_byte(uint8_t device_index, uint8_t byte)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
@ -95,25 +72,141 @@ namespace Kernel::Input
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::device_send_byte(PS2Device* device, uint8_t byte)
|
||||
{
|
||||
ASSERT(device);
|
||||
ASSERT(device == m_devices[0].ptr() || device == m_devices[1].ptr());
|
||||
TRY(device_send_byte(device == m_devices[0].ptr() ? 0 : 1, byte));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::device_read_ack(uint8_t device_index)
|
||||
BAN::ErrorOr<void> PS2Controller::device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
if (TRY(read_byte()) != PS2::Response::ACK)
|
||||
for (;;)
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK", device_index);
|
||||
TRY(device_send_byte(device_index, byte));
|
||||
uint8_t response = TRY(read_byte());
|
||||
if (response == PS2::Response::RESEND)
|
||||
continue;
|
||||
if (response == PS2::Response::ACK)
|
||||
break;
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK, got {2H}", device_index, byte);
|
||||
return BAN::Error::from_errno(EBADMSG);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t response_size)
|
||||
{
|
||||
// NOTE: command queue push/pop must be done without interrupts
|
||||
CriticalScope _;
|
||||
ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr()));
|
||||
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
|
||||
{
|
||||
dprintln("PS/2 command queue full");
|
||||
return false;
|
||||
}
|
||||
m_command_queue.push(Command {
|
||||
.state = Command::State::NotSent,
|
||||
.device_index = (device == m_devices[0].ptr()) ? uint8_t(0) : uint8_t(1),
|
||||
.out_data = { command, 0x00 },
|
||||
.out_count = 1,
|
||||
.in_count = response_size,
|
||||
.send_index = 0
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t data, uint8_t response_size)
|
||||
{
|
||||
// NOTE: command queue push/pop must be done without interrupts
|
||||
CriticalScope _;
|
||||
ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr()));
|
||||
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
|
||||
{
|
||||
dprintln("PS/2 command queue full");
|
||||
return false;
|
||||
}
|
||||
m_command_queue.push(Command {
|
||||
.state = Command::State::NotSent,
|
||||
.device_index = (device == m_devices[0].ptr()) ? uint8_t(0) : uint8_t(1),
|
||||
.out_data = { command, data },
|
||||
.out_count = 2,
|
||||
.in_count = response_size,
|
||||
.send_index = 0
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void PS2Controller::update_command_queue()
|
||||
{
|
||||
ASSERT(interrupts_enabled());
|
||||
|
||||
if (m_command_queue.empty())
|
||||
return;
|
||||
auto& command = m_command_queue.front();
|
||||
if (command.state == Command::State::WaitingResponse || command.state == Command::State::WaitingAck)
|
||||
return;
|
||||
ASSERT(command.send_index < command.out_count);
|
||||
command.state = Command::State::WaitingAck;
|
||||
if (auto ret = device_send_byte(command.device_index, command.out_data[command.send_index]); ret.is_error())
|
||||
{
|
||||
command.state = Command::State::Sending;
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 send command byte: {}", ret.error());
|
||||
}
|
||||
}
|
||||
|
||||
bool PS2Controller::handle_command_byte(PS2Device* device, uint8_t byte)
|
||||
{
|
||||
// NOTE: command queue push/pop must be done without interrupts
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
if (m_command_queue.empty())
|
||||
return false;
|
||||
auto& command = m_command_queue.front();
|
||||
|
||||
ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr()));
|
||||
if (command.device_index != (device == m_devices[0].ptr()) ? 0 : 1)
|
||||
return false;
|
||||
|
||||
switch (command.state)
|
||||
{
|
||||
case Command::State::NotSent:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case Command::State::Sending:
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device sent byte while middle of command send");
|
||||
return false;
|
||||
}
|
||||
case Command::State::WaitingResponse:
|
||||
{
|
||||
if (--command.in_count <= 0)
|
||||
m_command_queue.pop();
|
||||
return false;
|
||||
}
|
||||
case Command::State::WaitingAck:
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
case PS2::Response::ACK:
|
||||
{
|
||||
if (++command.send_index < command.out_count)
|
||||
command.state = Command::State::Sending;
|
||||
else if (command.in_count > 0)
|
||||
command.state = Command::State::WaitingResponse;
|
||||
else
|
||||
m_command_queue.pop();
|
||||
return true;
|
||||
}
|
||||
case PS2::Response::RESEND:
|
||||
command.state = Command::State::Sending;
|
||||
return true;
|
||||
default:
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 expected ACK got {2H}", byte);
|
||||
command.state = Command::State::Sending;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
|
@ -134,21 +227,25 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_impl()
|
||||
{
|
||||
// Step 1: Initialise USB Controllers
|
||||
// FIXME
|
||||
// FIXME: Initialise USB Controllers
|
||||
|
||||
// Step 2: Determine if the PS/2 Controller Exists
|
||||
// FIXME
|
||||
// Determine if the PS/2 Controller Exists
|
||||
auto* fadt = static_cast<const ACPI::FADT*>(ACPI::get().get_header("FACP"sv, 0));
|
||||
if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1)))
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "No PS/2 available");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Step 3: Disable Devices
|
||||
// Disable Devices
|
||||
TRY(send_command(PS2::Command::DISABLE_FIRST_PORT));
|
||||
TRY(send_command(PS2::Command::DISABLE_SECOND_PORT));
|
||||
|
||||
// Step 4: Flush The Output Buffer
|
||||
// Flush The Output Buffer
|
||||
while (!read_byte().is_error())
|
||||
continue;
|
||||
|
||||
// Step 5: Set the Controller Configuration Byte
|
||||
// Set the Controller Configuration Byte
|
||||
TRY(send_command(PS2::Command::READ_CONFIG));
|
||||
uint8_t config = TRY(read_byte());
|
||||
config &= ~PS2::Config::INTERRUPT_FIRST_PORT;
|
||||
|
@ -156,7 +253,7 @@ namespace Kernel::Input
|
|||
config &= ~PS2::Config::TRANSLATION_FIRST_PORT;
|
||||
TRY(send_command(PS2::Command::WRITE_CONFIG, config));
|
||||
|
||||
// Step 6: Perform Controller Self Test
|
||||
// Perform Controller Self Test
|
||||
TRY(send_command(PS2::Command::TEST_CONTROLLER));
|
||||
if (TRY(read_byte()) != PS2::Response::TEST_CONTROLLER_PASS)
|
||||
{
|
||||
|
@ -166,7 +263,7 @@ namespace Kernel::Input
|
|||
// NOTE: self test might reset the device so we set the config byte again
|
||||
TRY(send_command(PS2::Command::WRITE_CONFIG, config));
|
||||
|
||||
// Step 7: Determine If There Are 2 Channels
|
||||
// Determine If There Are 2 Channels
|
||||
bool valid_ports[2] { true, false };
|
||||
if (config & PS2::Config::CLOCK_SECOND_PORT)
|
||||
{
|
||||
|
@ -179,7 +276,7 @@ namespace Kernel::Input
|
|||
}
|
||||
}
|
||||
|
||||
// Step 8: Perform Interface Tests
|
||||
// Perform Interface Tests
|
||||
TRY(send_command(PS2::Command::TEST_FIRST_PORT));
|
||||
if (TRY(read_byte()) != PS2::Response::TEST_FIRST_PORT_PASS)
|
||||
{
|
||||
|
@ -197,49 +294,29 @@ namespace Kernel::Input
|
|||
}
|
||||
if (!valid_ports[0] && !valid_ports[1])
|
||||
return {};
|
||||
|
||||
// Step 9: Enable Devices (and disable scanning)
|
||||
for (uint8_t device = 0; device < 2; device++)
|
||||
{
|
||||
if (!valid_ports[device])
|
||||
continue;
|
||||
TRY(send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT));
|
||||
if (set_scanning(device, false).is_error())
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 could not disable device scanning");
|
||||
valid_ports[device] = false;
|
||||
}
|
||||
TRY(send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT));
|
||||
}
|
||||
|
||||
// Step 10: Reset Devices
|
||||
// Initialize devices
|
||||
for (uint8_t device = 0; device < 2; device++)
|
||||
{
|
||||
if (!valid_ports[device])
|
||||
continue;
|
||||
if (auto ret = reset_device(device); ret.is_error())
|
||||
if (auto ret = send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); ret.is_error())
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device reset failed: {}", ret.error());
|
||||
valid_ports[device] = false;
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error());
|
||||
continue;
|
||||
}
|
||||
if (auto ret = set_scanning(device, false); ret.is_error())
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device scan disabling failed: {}", ret.error());
|
||||
valid_ports[device] = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 11: Initialize Device Drivers
|
||||
for (uint8_t device = 0; device < 2; device++)
|
||||
{
|
||||
if (!valid_ports[device])
|
||||
continue;
|
||||
if (auto res = initialize_device(device); res.is_error())
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error());
|
||||
(void)send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_devices[0] && !m_devices[1])
|
||||
return {};
|
||||
|
||||
// Enable irqs on valid devices
|
||||
if (m_devices[0])
|
||||
{
|
||||
m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
|
||||
|
@ -255,6 +332,7 @@ namespace Kernel::Input
|
|||
|
||||
TRY(send_command(PS2::Command::WRITE_CONFIG, config));
|
||||
|
||||
// Send device initialization sequence after interrupts are enabled
|
||||
for (uint8_t device = 0; device < 2; device++)
|
||||
{
|
||||
if (!m_devices[device])
|
||||
|
@ -268,9 +346,25 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device)
|
||||
{
|
||||
TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY));
|
||||
TRY(device_read_ack(device));
|
||||
// Reset device
|
||||
TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET));
|
||||
if (TRY(read_byte()) != PS2::Response::SELF_TEST_PASS)
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device self test failed");
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
while (!read_byte().is_error())
|
||||
continue;
|
||||
|
||||
// Disable scanning and flush buffer
|
||||
TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::DISABLE_SCANNING));
|
||||
while (!read_byte().is_error())
|
||||
continue;
|
||||
|
||||
// Identify device
|
||||
TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::IDENTIFY));
|
||||
|
||||
// Read up to 2 identification bytes
|
||||
uint8_t bytes[2] {};
|
||||
uint8_t index = 0;
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
|
@ -286,41 +380,19 @@ namespace Kernel::Input
|
|||
{
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found mouse");
|
||||
m_devices[device] = TRY(PS2Mouse::create(*this));
|
||||
return {};
|
||||
}
|
||||
|
||||
// MF2 Keyboard
|
||||
else if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83))
|
||||
if (index == 2 && (bytes[0] == 0xAB && (bytes[1] == 0x83 || bytes[1] == 0x41)))
|
||||
{
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found keyboard");
|
||||
m_devices[device] = TRY(PS2Keyboard::create(*this));
|
||||
}
|
||||
|
||||
if (m_devices[device])
|
||||
return {};
|
||||
}
|
||||
|
||||
dprintln_if(DEBUG_PS2, "PS/2 unsupported device {2H} {2H} ({} bytes) on port {}", bytes[0], bytes[1], index, device);
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device)
|
||||
{
|
||||
TRY(device_send_byte(device, PS2::DeviceCommand::RESET));
|
||||
TRY(device_read_ack(device));
|
||||
if (TRY(read_byte()) != PS2::Response::SELF_TEST_PASS)
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device self test failed");
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
// device might send extra data
|
||||
while (!read_byte().is_error())
|
||||
continue;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::set_scanning(uint8_t device, bool enabled)
|
||||
{
|
||||
TRY(device_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING));
|
||||
TRY(device_read_ack(device));
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,114 +17,19 @@ namespace Kernel::Input
|
|||
|
||||
bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size)
|
||||
{
|
||||
CriticalScope _;
|
||||
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
|
||||
{
|
||||
dprintln("PS/2 command queue full");
|
||||
return false;
|
||||
}
|
||||
m_command_queue.push(Command {
|
||||
.out_data = { command, 0x00 },
|
||||
.out_count = 1,
|
||||
.in_count = response_size,
|
||||
.send_index = 0
|
||||
});
|
||||
update_command();
|
||||
return true;
|
||||
return m_controller.append_command_queue(this, command, response_size);
|
||||
}
|
||||
|
||||
bool PS2Device::append_command_queue(uint8_t command, uint8_t data, uint8_t response_size)
|
||||
{
|
||||
CriticalScope _;
|
||||
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
|
||||
{
|
||||
dprintln("PS/2 command queue full");
|
||||
return false;
|
||||
}
|
||||
m_command_queue.push(Command {
|
||||
.out_data = { command, data },
|
||||
.out_count = 2,
|
||||
.in_count = response_size,
|
||||
.send_index = 0
|
||||
});
|
||||
update_command();
|
||||
return true;
|
||||
return m_controller.append_command_queue(this, command, data, response_size);
|
||||
}
|
||||
|
||||
void PS2Device::handle_irq()
|
||||
{
|
||||
uint8_t byte = IO::inb(PS2::IOPort::DATA);
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case State::WaitingAck:
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
case PS2::Response::ACK:
|
||||
{
|
||||
auto& command = m_command_queue.front();
|
||||
if (++command.send_index < command.out_count)
|
||||
m_state = State::Normal;
|
||||
else if (command.in_count > 0)
|
||||
m_state = State::WaitingResponse;
|
||||
else
|
||||
{
|
||||
m_command_queue.pop();
|
||||
m_state = State::Normal;
|
||||
m_controller.unlock_command(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PS2::Response::RESEND:
|
||||
m_state = State::Normal;
|
||||
break;
|
||||
default:
|
||||
handle_device_command_response(byte);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::WaitingResponse:
|
||||
{
|
||||
if (--m_command_queue.front().in_count <= 0)
|
||||
{
|
||||
m_command_queue.pop();
|
||||
m_state = State::Normal;
|
||||
m_controller.unlock_command(this);
|
||||
}
|
||||
handle_byte(byte);
|
||||
break;
|
||||
}
|
||||
case State::Normal:
|
||||
{
|
||||
handle_byte(byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_command();
|
||||
}
|
||||
|
||||
void PS2Device::update_command()
|
||||
{
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
if (m_state != State::Normal)
|
||||
return;
|
||||
if (m_command_queue.empty())
|
||||
return;
|
||||
|
||||
const auto& command = m_command_queue.front();
|
||||
ASSERT(command.send_index < command.out_count);
|
||||
|
||||
if (!m_controller.lock_command(this))
|
||||
return;
|
||||
|
||||
m_state = State::WaitingAck;
|
||||
auto ret = m_controller.device_send_byte(this, command.out_data[command.send_index]);
|
||||
if (ret.is_error())
|
||||
dwarnln("Could not send byte to device: {}", ret.error());
|
||||
if (!m_controller.handle_command_byte(this, byte))
|
||||
handle_byte(byte);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,22 +30,14 @@ namespace Kernel::Input
|
|||
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
|
||||
}
|
||||
|
||||
void PS2Keyboard::handle_device_command_response(uint8_t byte)
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
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:
|
||||
dwarnln("Unhandeled byte {2H}", byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PS2Keyboard::handle_byte(uint8_t byte)
|
||||
{
|
||||
if (byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1 || byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2)
|
||||
{
|
||||
dwarnln("Key detection error or internal buffer overrun");
|
||||
return;
|
||||
}
|
||||
|
||||
m_byte_buffer[m_byte_index++] = byte;
|
||||
if (byte == 0xE0 || byte == 0xF0)
|
||||
return;
|
||||
|
|
|
@ -70,16 +70,6 @@ namespace Kernel::Input
|
|||
}
|
||||
}
|
||||
|
||||
void PS2Mouse::handle_device_command_response(uint8_t byte)
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
default:
|
||||
dwarnln("Unhandeled byte {2H}", byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PS2Mouse::handle_byte(uint8_t byte)
|
||||
{
|
||||
if (!m_enabled)
|
||||
|
|
Loading…
Reference in New Issue