Kernel: Do a big rewrite of PS/2 code

Command sending+response reading is now synchronized. This allows
bochs to properly initialize both mouse and keyboard simultaneously.

Also status register is checked EVERY time read/write to other IO
ports is performed.
This commit is contained in:
Bananymous 2024-01-07 17:25:06 +02:00
parent 2fec718590
commit d760239748
9 changed files with 264 additions and 124 deletions

View File

@ -11,10 +11,6 @@ namespace Kernel
ACPI_NoRootSDT, ACPI_NoRootSDT,
ACPI_NoSuchHeader, ACPI_NoSuchHeader,
ACPI_RootInvalid, ACPI_RootInvalid,
PS2_Timeout,
PS2_SelfTest,
PS2_Reset,
PS2_UnsupportedDevice,
Ext2_Invalid, Ext2_Invalid,
Ext2_Corrupted, Ext2_Corrupted,
Ext2_NoInodes, Ext2_NoInodes,

View File

@ -14,8 +14,8 @@ namespace Kernel::Input::PS2
enum Status : uint8_t enum Status : uint8_t
{ {
OUTPUT_FULL = (1 << 0), OUTPUT_STATUS = (1 << 0),
INPUT_FULL = (1 << 1), INPUT_STATUS = (1 << 1),
SYSTEM = (1 << 2), SYSTEM = (1 << 2),
DEVICE_OR_CONTROLLER = (1 << 3), DEVICE_OR_CONTROLLER = (1 << 3),
TIMEOUT_ERROR = (1 << 6), TIMEOUT_ERROR = (1 << 6),

View File

@ -1,8 +1,10 @@
#pragma once #pragma once
#include <BAN/CircularQueue.h> #include <BAN/UniqPtr.h>
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/SpinLock.h>
namespace Kernel::Input namespace Kernel::Input
{ {
@ -15,7 +17,10 @@ namespace Kernel::Input
static BAN::ErrorOr<void> initialize(); static BAN::ErrorOr<void> initialize();
static PS2Controller& get(); static PS2Controller& get();
void send_byte(const PS2Device*, uint8_t); BAN::ErrorOr<void> device_send_byte(PS2Device* device, uint8_t byte);
[[nodiscard]] bool lock_command(PS2Device*);
void unlock_command(PS2Device*);
private: private:
PS2Controller() = default; PS2Controller() = default;
@ -25,8 +30,21 @@ namespace Kernel::Input
BAN::ErrorOr<void> reset_device(uint8_t); BAN::ErrorOr<void> reset_device(uint8_t);
BAN::ErrorOr<void> set_scanning(uint8_t, bool); 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);
BAN::ErrorOr<void> send_command(PS2::Command command);
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);
private: private:
PS2Device* m_devices[2] { nullptr, nullptr }; BAN::RefPtr<PS2Device> m_devices[2];
RecursiveSpinLock m_lock;
PS2Device* m_executing_device { nullptr };
PS2Device* m_pending_device { nullptr };
}; };
} }

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <BAN/CircularQueue.h>
#include <kernel/Input/PS2/Controller.h> #include <kernel/Input/PS2/Controller.h>
#include <kernel/InterruptController.h>
namespace Kernel::Input namespace Kernel::Input
{ {
@ -13,8 +15,8 @@ namespace Kernel::Input
virtual void send_initialize() = 0; virtual void send_initialize() = 0;
bool append_command_queue(uint8_t command); bool append_command_queue(uint8_t command, uint8_t response_size);
bool append_command_queue(uint8_t command, uint8_t data); bool append_command_queue(uint8_t command, uint8_t data, uint8_t response_size);
virtual void handle_irq() final override; virtual void handle_irq() final override;
virtual void handle_byte(uint8_t) = 0; virtual void handle_byte(uint8_t) = 0;
@ -24,13 +26,22 @@ namespace Kernel::Input
virtual dev_t rdev() const final override { return m_rdev; } virtual dev_t rdev() const final override { return m_rdev; }
private: private:
void update(); void update_command();
private: private:
enum class State enum class State
{ {
Normal, Normal,
WaitingAck, WaitingAck,
WaitingResponse,
};
struct Command
{
uint8_t out_data[2];
uint8_t out_count;
uint8_t in_count;
uint8_t send_index;
}; };
private: private:
@ -39,7 +50,9 @@ namespace Kernel::Input
PS2Controller& m_controller; PS2Controller& m_controller;
State m_state = State::Normal; State m_state = State::Normal;
BAN::CircularQueue<uint8_t, 10> m_command_queue; BAN::CircularQueue<Command, 10> m_command_queue;
friend class PS2Controller;
}; };
} }

View File

@ -8,10 +8,6 @@ namespace Kernel
"ACPI could not find root SDT header"sv, "ACPI could not find root SDT header"sv,
"ACPI no such header"sv, "ACPI no such header"sv,
"ACPI root invalid", "ACPI root invalid",
"PS/2 device timeout"sv,
"PS/2 controller self test failed"sv,
"PS/2 reset failed"sv,
"PS/2 unsupported device"sv,
"Invalid ext2 filesystem"sv, "Invalid ext2 filesystem"sv,
"Ext2 filesystem corrupted"sv, "Ext2 filesystem corrupted"sv,
"Ext2 filesystem out of inodes"sv, "Ext2 filesystem out of inodes"sv,

View File

@ -10,64 +10,109 @@
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#define DEBUG_PS2 1
namespace Kernel::Input namespace Kernel::Input
{ {
static constexpr uint64_t s_device_timeout_ms = 100; static constexpr uint64_t s_ps2_timeout_ms = 100;
static void controller_send_command(PS2::Command command) static PS2Controller* s_instance = nullptr;
{
IO::outb(PS2::IOPort::COMMAND, command);
}
static void controller_send_command(PS2::Command command, uint8_t data) BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte)
{ {
IO::outb(PS2::IOPort::COMMAND, command); LockGuard _(m_lock);
while (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL) uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
continue;
IO::outb(PS2::IOPort::DATA, data);
}
static uint8_t wait_and_read()
{
while (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL))
continue;
return IO::inb(PS2::IOPort::DATA);
}
static BAN::ErrorOr<void> device_send_byte(uint8_t device, uint8_t byte)
{
if (device == 1)
IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT);
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_device_timeout_ms;
while (SystemTimer::get().ms_since_boot() < timeout) while (SystemTimer::get().ms_since_boot() < timeout)
{ {
if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)) if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_STATUS)
{ continue;
IO::outb(PS2::IOPort::DATA, byte); IO::outb(port, byte);
return {}; return {};
}
} }
return BAN::Error::from_error_code(ErrorCode::PS2_Timeout); return BAN::Error::from_errno(ETIMEDOUT);
} }
static BAN::ErrorOr<uint8_t> device_read_byte() BAN::ErrorOr<uint8_t> PS2Controller::read_byte()
{ {
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_device_timeout_ms; LockGuard _(m_lock);
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
while (SystemTimer::get().ms_since_boot() < timeout) while (SystemTimer::get().ms_since_boot() < timeout)
if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL) {
return IO::inb(PS2::IOPort::DATA); if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_STATUS))
return BAN::Error::from_error_code(ErrorCode::PS2_Timeout); continue;
return IO::inb(PS2::IOPort::DATA);
}
return BAN::Error::from_errno(ETIMEDOUT);
} }
static BAN::ErrorOr<void> device_wait_ack() BAN::ErrorOr<void> PS2Controller::send_command(PS2::Command command)
{ {
while (TRY(device_read_byte()) != PS2::Response::ACK) LockGuard _(m_lock);
continue;; TRY(send_byte(PS2::IOPort::COMMAND, command));
return {}; return {};
} }
static PS2Controller* s_instance = nullptr; BAN::ErrorOr<void> PS2Controller::send_command(PS2::Command command, uint8_t data)
{
LockGuard _(m_lock);
TRY(send_byte(PS2::IOPort::COMMAND, command));
TRY(send_byte(PS2::IOPort::DATA, data));
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);
if (device_index == 1)
TRY(send_byte(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT));
TRY(send_byte(PS2::IOPort::DATA, byte));
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)
{
LockGuard _(m_lock);
if (TRY(read_byte()) != PS2::Response::ACK)
{
dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK", device_index);
return BAN::Error::from_errno(EBADMSG);
}
return {};
}
BAN::ErrorOr<void> PS2Controller::initialize() BAN::ErrorOr<void> PS2Controller::initialize()
{ {
@ -96,47 +141,59 @@ namespace Kernel::Input
// FIXME // FIXME
// Step 3: Disable Devices // Step 3: Disable Devices
controller_send_command(PS2::Command::DISABLE_FIRST_PORT); TRY(send_command(PS2::Command::DISABLE_FIRST_PORT));
controller_send_command(PS2::Command::DISABLE_SECOND_PORT); TRY(send_command(PS2::Command::DISABLE_SECOND_PORT));
// Step 4: Flush The Output Buffer // Step 4: Flush The Output Buffer
IO::inb(PS2::IOPort::DATA); while (!read_byte().is_error())
continue;
// Step 5: Set the Controller Configuration Byte // Step 5: Set the Controller Configuration Byte
controller_send_command(PS2::Command::READ_CONFIG); TRY(send_command(PS2::Command::READ_CONFIG));
uint8_t config = wait_and_read(); uint8_t config = TRY(read_byte());
config &= ~PS2::Config::INTERRUPT_FIRST_PORT; config &= ~PS2::Config::INTERRUPT_FIRST_PORT;
config &= ~PS2::Config::INTERRUPT_SECOND_PORT; config &= ~PS2::Config::INTERRUPT_SECOND_PORT;
config &= ~PS2::Config::TRANSLATION_FIRST_PORT; config &= ~PS2::Config::TRANSLATION_FIRST_PORT;
controller_send_command(PS2::Command::WRITE_CONFIG, config); TRY(send_command(PS2::Command::WRITE_CONFIG, config));
// Step 6: Perform Controller Self Test // Step 6: Perform Controller Self Test
controller_send_command(PS2::Command::TEST_CONTROLLER); TRY(send_command(PS2::Command::TEST_CONTROLLER));
if (wait_and_read() != PS2::Response::TEST_CONTROLLER_PASS) if (TRY(read_byte()) != PS2::Response::TEST_CONTROLLER_PASS)
return BAN::Error::from_error_code(ErrorCode::PS2_SelfTest); {
dwarnln_if(DEBUG_PS2, "PS/2 Controller test failed");
return BAN::Error::from_errno(ENODEV);
}
// NOTE: self test might reset the device so we set the config byte again // NOTE: self test might reset the device so we set the config byte again
controller_send_command(PS2::Command::WRITE_CONFIG, config); TRY(send_command(PS2::Command::WRITE_CONFIG, config));
// Step 7: Determine If There Are 2 Channels // Step 7: Determine If There Are 2 Channels
bool valid_ports[2] { true, false }; bool valid_ports[2] { true, false };
if (config & PS2::Config::CLOCK_SECOND_PORT) if (config & PS2::Config::CLOCK_SECOND_PORT)
{ {
controller_send_command(PS2::Command::ENABLE_SECOND_PORT); TRY(send_command(PS2::Command::ENABLE_SECOND_PORT));
controller_send_command(PS2::Command::READ_CONFIG); TRY(send_command(PS2::Command::READ_CONFIG));
if (!(wait_and_read() & PS2::Config::CLOCK_SECOND_PORT)) if (!(TRY(read_byte()) & PS2::Config::CLOCK_SECOND_PORT))
{
valid_ports[1] = true; valid_ports[1] = true;
controller_send_command(PS2::Command::DISABLE_SECOND_PORT); TRY(send_command(PS2::Command::DISABLE_SECOND_PORT));
}
} }
// Step 8: Perform Interface Tests // Step 8: Perform Interface Tests
controller_send_command(PS2::Command::TEST_FIRST_PORT); TRY(send_command(PS2::Command::TEST_FIRST_PORT));
if (wait_and_read() != PS2::Response::TEST_FIRST_PORT_PASS) if (TRY(read_byte()) != PS2::Response::TEST_FIRST_PORT_PASS)
{
dwarnln_if(DEBUG_PS2, "PS/2 first port test failed");
valid_ports[0] = false; valid_ports[0] = false;
}
if (valid_ports[1]) if (valid_ports[1])
{ {
controller_send_command(PS2::Command::TEST_SECOND_PORT); TRY(send_command(PS2::Command::TEST_SECOND_PORT));
if (wait_and_read() != PS2::Response::TEST_SECOND_PORT_PASS) if (TRY(read_byte()) != PS2::Response::TEST_SECOND_PORT_PASS)
{
dwarnln_if(DEBUG_PS2, "PS/2 second port test failed");
valid_ports[1] = false; valid_ports[1] = false;
}
} }
if (!valid_ports[0] && !valid_ports[1]) if (!valid_ports[0] && !valid_ports[1])
return {}; return {};
@ -146,9 +203,13 @@ namespace Kernel::Input
{ {
if (!valid_ports[device]) if (!valid_ports[device])
continue; continue;
controller_send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); TRY(send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT));
if (set_scanning(device, false).is_error()) if (set_scanning(device, false).is_error())
{
dwarnln_if(DEBUG_PS2, "PS/2 could not disable device scanning");
valid_ports[device] = false; valid_ports[device] = false;
}
TRY(send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT));
} }
// Step 10: Reset Devices // Step 10: Reset Devices
@ -156,10 +217,18 @@ namespace Kernel::Input
{ {
if (!valid_ports[device]) if (!valid_ports[device])
continue; continue;
if (reset_device(device).is_error()) if (auto ret = reset_device(device); ret.is_error())
{
dwarnln_if(DEBUG_PS2, "PS/2 device reset failed: {}", ret.error());
valid_ports[device] = false; valid_ports[device] = false;
if (set_scanning(device, false).is_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; valid_ports[device] = false;
continue;
}
} }
// Step 11: Initialize Device Drivers // Step 11: Initialize Device Drivers
@ -168,7 +237,7 @@ namespace Kernel::Input
if (!valid_ports[device]) if (!valid_ports[device])
continue; continue;
if (auto res = initialize_device(device); res.is_error()) if (auto res = initialize_device(device); res.is_error())
dprintln("{}", res.error()); dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error());
} }
if (m_devices[0]) if (m_devices[0])
@ -184,11 +253,11 @@ namespace Kernel::Input
config |= PS2::Config::INTERRUPT_SECOND_PORT; config |= PS2::Config::INTERRUPT_SECOND_PORT;
} }
controller_send_command(PS2::Command::WRITE_CONFIG, config); TRY(send_command(PS2::Command::WRITE_CONFIG, config));
for (uint8_t device = 0; device < 2; device++) for (uint8_t device = 0; device < 2; device++)
{ {
if (m_devices[device] == nullptr) if (!m_devices[device])
continue; continue;
m_devices[device]->send_initialize(); m_devices[device]->send_initialize();
DevFileSystem::get().add_device(m_devices[device]); DevFileSystem::get().add_device(m_devices[device]);
@ -200,13 +269,13 @@ namespace Kernel::Input
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device) BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device)
{ {
TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY)); TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY));
TRY(device_wait_ack()); TRY(device_read_ack(device));
uint8_t bytes[2] {}; uint8_t bytes[2] {};
uint8_t index = 0; uint8_t index = 0;
for (uint8_t i = 0; i < 2; i++) for (uint8_t i = 0; i < 2; i++)
{ {
auto res = device_read_byte(); auto res = read_byte();
if (res.is_error()) if (res.is_error())
break; break;
bytes[index++] = res.value(); bytes[index++] = res.value();
@ -214,37 +283,43 @@ namespace Kernel::Input
// Standard PS/2 Mouse // Standard PS/2 Mouse
if (index == 1 && (bytes[0] == 0x00)) if (index == 1 && (bytes[0] == 0x00))
{
dprintln_if(DEBUG_PS2, "PS/2 found mouse");
m_devices[device] = TRY(PS2Mouse::create(*this)); m_devices[device] = TRY(PS2Mouse::create(*this));
}
// MF2 Keyboard // MF2 Keyboard
else if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83)) else if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83))
{
dprintln_if(DEBUG_PS2, "PS/2 found keyboard");
m_devices[device] = TRY(PS2Keyboard::create(*this)); m_devices[device] = TRY(PS2Keyboard::create(*this));
}
if (m_devices[device]) if (m_devices[device])
return {}; return {};
return BAN::Error::from_error_code(ErrorCode::PS2_UnsupportedDevice); 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);
void PS2Controller::send_byte(const PS2Device* device, uint8_t byte)
{
ASSERT(device != nullptr && (device == m_devices[0] || device == m_devices[1]));
uint8_t device_index = (device == m_devices[0]) ? 0 : 1;
MUST(device_send_byte(device_index, byte));
} }
BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device) BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device)
{ {
TRY(device_send_byte(device, PS2::DeviceCommand::RESET)); TRY(device_send_byte(device, PS2::DeviceCommand::RESET));
TRY(device_wait_ack()); TRY(device_read_ack(device));
if (TRY(device_read_byte()) != PS2::Response::SELF_TEST_PASS) if (TRY(read_byte()) != PS2::Response::SELF_TEST_PASS)
return BAN::Error::from_error_code(ErrorCode::PS2_Reset); {
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 {}; return {};
} }
BAN::ErrorOr<void> PS2Controller::set_scanning(uint8_t device, bool enabled) 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_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING));
TRY(device_wait_ack()); TRY(device_read_ack(device));
return {}; return {};
} }

View File

@ -15,28 +15,39 @@ namespace Kernel::Input
, m_controller(controller) , m_controller(controller)
{ } { }
bool PS2Device::append_command_queue(uint8_t command) bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size)
{ {
CriticalScope _;
if (m_command_queue.size() + 1 >= m_command_queue.capacity()) if (m_command_queue.size() + 1 >= m_command_queue.capacity())
{ {
dprintln("PS/2 command queue full"); dprintln("PS/2 command queue full");
return false; return false;
} }
m_command_queue.push(command); m_command_queue.push(Command {
update(); .out_data = { command, 0x00 },
.out_count = 1,
.in_count = response_size,
.send_index = 0
});
update_command();
return true; return true;
} }
bool PS2Device::append_command_queue(uint8_t command, uint8_t data) bool PS2Device::append_command_queue(uint8_t command, uint8_t data, uint8_t response_size)
{ {
if (m_command_queue.size() + 2 >= m_command_queue.capacity()) CriticalScope _;
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
{ {
dprintln("PS/2 command queue full"); dprintln("PS/2 command queue full");
return false; return false;
} }
m_command_queue.push(command); m_command_queue.push(Command {
m_command_queue.push(data); .out_data = { command, data },
update(); .out_count = 2,
.in_count = response_size,
.send_index = 0
});
update_command();
return true; return true;
} }
@ -44,8 +55,6 @@ namespace Kernel::Input
{ {
uint8_t byte = IO::inb(PS2::IOPort::DATA); 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) switch (m_state)
{ {
case State::WaitingAck: case State::WaitingAck:
@ -53,9 +62,20 @@ namespace Kernel::Input
switch (byte) switch (byte)
{ {
case PS2::Response::ACK: case PS2::Response::ACK:
m_command_queue.pop(); {
m_state = State::Normal; 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; break;
}
case PS2::Response::RESEND: case PS2::Response::RESEND:
m_state = State::Normal; m_state = State::Normal;
break; break;
@ -65,6 +85,17 @@ namespace Kernel::Input
} }
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: case State::Normal:
{ {
handle_byte(byte); handle_byte(byte);
@ -72,17 +103,28 @@ namespace Kernel::Input
} }
} }
update(); update_command();
} }
void PS2Device::update() void PS2Device::update_command()
{ {
if (m_state == State::WaitingAck) ASSERT(!interrupts_enabled());
if (m_state != State::Normal)
return; return;
if (m_command_queue.empty()) if (m_command_queue.empty())
return; 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; m_state = State::WaitingAck;
m_controller.send_byte(this, m_command_queue.front()); 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());
} }
} }

View File

@ -25,9 +25,9 @@ namespace Kernel::Input
void PS2Keyboard::send_initialize() void PS2Keyboard::send_initialize()
{ {
append_command_queue(Command::SET_LEDS, 0x00); append_command_queue(Command::SET_LEDS, 0x00, 0);
append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2); append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2, 0);
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING); append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
} }
void PS2Keyboard::handle_device_command_response(uint8_t byte) void PS2Keyboard::handle_device_command_response(uint8_t byte)
@ -148,7 +148,7 @@ namespace Kernel::Input
new_leds |= PS2::KBLeds::NUM_LOCK; new_leds |= PS2::KBLeds::NUM_LOCK;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock) if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock)
new_leds |= PS2::KBLeds::CAPS_LOCK; new_leds |= PS2::KBLeds::CAPS_LOCK;
append_command_queue(Command::SET_LEDS, new_leds); append_command_queue(Command::SET_LEDS, new_leds, 0);
} }
BAN::ErrorOr<size_t> PS2Keyboard::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> PS2Keyboard::read_impl(off_t, BAN::ByteSpan buffer)

View File

@ -26,10 +26,10 @@ namespace Kernel::Input
void PS2Mouse::send_initialize() void PS2Mouse::send_initialize()
{ {
// Query extensions // Query extensions
append_command_queue(Command::SET_SAMPLE_RATE, 200); append_command_queue(Command::SET_SAMPLE_RATE, 200, 0);
append_command_queue(Command::SET_SAMPLE_RATE, 100); append_command_queue(Command::SET_SAMPLE_RATE, 100, 0);
append_command_queue(Command::SET_SAMPLE_RATE, 80); append_command_queue(Command::SET_SAMPLE_RATE, 80, 0);
append_command_queue(PS2::DeviceCommand::IDENTIFY); append_command_queue(PS2::DeviceCommand::IDENTIFY, 1);
} }
void PS2Mouse::initialize_extensions(uint8_t byte) void PS2Mouse::initialize_extensions(uint8_t byte)
@ -48,10 +48,10 @@ namespace Kernel::Input
else else
{ {
m_mouse_id = 0x03; m_mouse_id = 0x03;
append_command_queue(Command::SET_SAMPLE_RATE, 200); append_command_queue(Command::SET_SAMPLE_RATE, 200, 0);
append_command_queue(Command::SET_SAMPLE_RATE, 200); append_command_queue(Command::SET_SAMPLE_RATE, 200, 0);
append_command_queue(Command::SET_SAMPLE_RATE, 80); append_command_queue(Command::SET_SAMPLE_RATE, 80, 0);
append_command_queue(PS2::DeviceCommand::IDENTIFY); append_command_queue(PS2::DeviceCommand::IDENTIFY, 1);
} }
break; break;
case 0x04: case 0x04:
@ -65,8 +65,8 @@ namespace Kernel::Input
if (m_enabled) if (m_enabled)
{ {
append_command_queue(Command::SET_SAMPLE_RATE, 100); append_command_queue(Command::SET_SAMPLE_RATE, 100, 0);
append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING); append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0);
} }
} }