forked from Bananymous/banan-os
Kernel: Unify PS2Device to handle commands instead of inherited
This commit is contained in:
parent
d2d12d5281
commit
8f8d6bddc0
|
@ -55,6 +55,7 @@ namespace Kernel::Input::PS2
|
|||
TEST_CONTROLLER_PASS = 0x55,
|
||||
SELF_TEST_PASS = 0xAA,
|
||||
ACK = 0xFA,
|
||||
RESEND = 0xFE,
|
||||
};
|
||||
|
||||
enum DeviceCommand : uint8_t
|
||||
|
@ -74,9 +75,6 @@ namespace Kernel::Input::PS2
|
|||
enum KBResponse : uint8_t
|
||||
{
|
||||
KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00,
|
||||
SELF_TEST_PASSED = 0xAA,
|
||||
ECHO_RESPONSE = 0xEE,
|
||||
RESEND = 0xFE,
|
||||
KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,23 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <kernel/Device/Device.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
|
||||
namespace Kernel::Input
|
||||
{
|
||||
|
||||
class PS2Controller;
|
||||
|
||||
class PS2Device : public CharacterDevice, public Interruptable
|
||||
{
|
||||
public:
|
||||
PS2Device();
|
||||
PS2Device(PS2Controller&);
|
||||
virtual ~PS2Device() {}
|
||||
|
||||
virtual void send_initialize() = 0;
|
||||
|
||||
bool append_command_queue(uint8_t command);
|
||||
bool append_command_queue(uint8_t command, uint8_t data);
|
||||
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 override { return m_name; }
|
||||
|
||||
protected:
|
||||
void update();
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
Normal,
|
||||
WaitingAck,
|
||||
};
|
||||
|
||||
private:
|
||||
const BAN::String m_name;
|
||||
|
||||
PS2Controller& m_controller;
|
||||
State m_state = State::Normal;
|
||||
BAN::CircularQueue<uint8_t, 10> m_command_queue;
|
||||
};
|
||||
|
||||
class PS2Controller
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <kernel/Input/KeyEvent.h>
|
||||
#include <kernel/Input/PS2Controller.h>
|
||||
#include <kernel/Input/PS2Keymap.h>
|
||||
|
@ -15,48 +14,31 @@ namespace Kernel::Input
|
|||
enum Command : uint8_t
|
||||
{
|
||||
SET_LEDS = 0xED,
|
||||
SCANCODE = 0xF0,
|
||||
ENABLE_SCANNING = 0xF4,
|
||||
DISABLE_SCANNING = 0xF5,
|
||||
};
|
||||
|
||||
enum class State
|
||||
{
|
||||
Normal,
|
||||
WaitingAck,
|
||||
SCANCODE = 0xF0
|
||||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<PS2Keyboard*> create(PS2Controller&);
|
||||
virtual void send_initialize() override;
|
||||
|
||||
virtual void handle_irq() override;
|
||||
virtual void update() override;
|
||||
virtual void handle_byte(uint8_t) final override;
|
||||
virtual void handle_device_command_response(uint8_t) final override;
|
||||
|
||||
private:
|
||||
PS2Keyboard(PS2Controller& controller);
|
||||
|
||||
void append_command_queue(uint8_t);
|
||||
void append_command_queue(uint8_t, uint8_t);
|
||||
|
||||
void buffer_has_key();
|
||||
|
||||
void update_leds();
|
||||
|
||||
private:
|
||||
PS2Controller& m_controller;
|
||||
uint8_t m_byte_buffer[10];
|
||||
uint8_t m_byte_index { 0 };
|
||||
|
||||
uint8_t m_modifiers { 0 };
|
||||
|
||||
BAN::CircularQueue<KeyEvent, 10> m_event_queue;
|
||||
BAN::CircularQueue<uint8_t, 10> m_command_queue;
|
||||
|
||||
PS2Keymap m_keymap;
|
||||
|
||||
State m_state { State::Normal };
|
||||
|
||||
Semaphore m_semaphore;
|
||||
|
||||
public:
|
||||
|
|
|
@ -68,11 +68,6 @@ namespace Kernel::Input
|
|||
|
||||
static PS2Controller* s_instance = nullptr;
|
||||
|
||||
PS2Device::PS2Device()
|
||||
: CharacterDevice(0440, 0, 901)
|
||||
, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device()))
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
|
@ -253,4 +248,72 @@ namespace Kernel::Input
|
|||
return {};
|
||||
}
|
||||
|
||||
PS2Device::PS2Device(PS2Controller& controller)
|
||||
: CharacterDevice(0440, 0, 901)
|
||||
, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device()))
|
||||
, m_controller(controller)
|
||||
{ }
|
||||
|
||||
bool PS2Device::append_command_queue(uint8_t command)
|
||||
{
|
||||
if (m_command_queue.size() + 1 >= m_command_queue.capacity())
|
||||
return false;
|
||||
m_command_queue.push(command);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PS2Device::append_command_queue(uint8_t command, uint8_t data)
|
||||
{
|
||||
if (m_command_queue.size() + 2 >= m_command_queue.capacity())
|
||||
return false;
|
||||
m_command_queue.push(command);
|
||||
m_command_queue.push(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PS2Device::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)
|
||||
{
|
||||
case State::WaitingAck:
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
case PS2::Response::ACK:
|
||||
m_command_queue.pop();
|
||||
m_state = State::Normal;
|
||||
break;
|
||||
case PS2::Response::RESEND:
|
||||
m_state = State::Normal;
|
||||
break;
|
||||
default:
|
||||
handle_device_command_response(byte);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::Normal:
|
||||
{
|
||||
handle_byte(byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void PS2Device::update()
|
||||
{
|
||||
if (m_state == State::WaitingAck)
|
||||
return;
|
||||
if (m_command_queue.empty())
|
||||
return;
|
||||
m_state = State::WaitingAck;
|
||||
m_controller.send_byte(this, m_command_queue.front());
|
||||
}
|
||||
|
||||
}
|
|
@ -23,89 +23,38 @@ namespace Kernel::Input
|
|||
}
|
||||
|
||||
PS2Keyboard::PS2Keyboard(PS2Controller& controller)
|
||||
: m_controller(controller)
|
||||
: PS2Device(controller)
|
||||
, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
|
||||
{ }
|
||||
|
||||
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)
|
||||
{
|
||||
case State::WaitingAck:
|
||||
{
|
||||
switch (byte)
|
||||
{
|
||||
case PS2::Response::ACK:
|
||||
m_command_queue.pop();
|
||||
m_state = State::Normal;
|
||||
break;
|
||||
case PS2::KBResponse::RESEND:
|
||||
m_state = State::Normal;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::Normal:
|
||||
{
|
||||
m_byte_buffer[m_byte_index++] = byte;
|
||||
if (byte != 0xE0 && byte != 0xF0)
|
||||
buffer_has_key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PS2Keyboard::send_initialize()
|
||||
{
|
||||
append_command_queue(Command::SET_LEDS, 0x00);
|
||||
append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2);
|
||||
append_command_queue(Command::ENABLE_SCANNING);
|
||||
update();
|
||||
}
|
||||
|
||||
void PS2Keyboard::update()
|
||||
void PS2Keyboard::handle_device_command_response(uint8_t byte)
|
||||
{
|
||||
if (m_state == State::WaitingAck)
|
||||
return;
|
||||
if (m_command_queue.empty())
|
||||
return;
|
||||
m_state = State::WaitingAck;
|
||||
m_controller.send_byte(this, m_command_queue.front());
|
||||
}
|
||||
|
||||
void PS2Keyboard::append_command_queue(uint8_t byte)
|
||||
{
|
||||
if (m_command_queue.full())
|
||||
switch (byte)
|
||||
{
|
||||
dwarnln("PS/2 command queue full");
|
||||
return;
|
||||
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;
|
||||
}
|
||||
m_command_queue.push(byte);
|
||||
}
|
||||
|
||||
void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2)
|
||||
void PS2Keyboard::handle_byte(uint8_t byte)
|
||||
{
|
||||
if (m_command_queue.size() + 2 > m_command_queue.capacity())
|
||||
{
|
||||
dwarnln("PS/2 command queue full");
|
||||
m_byte_buffer[m_byte_index++] = byte;
|
||||
if (byte == 0xE0 || byte == 0xF0)
|
||||
return;
|
||||
}
|
||||
m_command_queue.push(byte1);
|
||||
m_command_queue.push(byte2);
|
||||
}
|
||||
|
||||
void PS2Keyboard::buffer_has_key()
|
||||
{
|
||||
uint32_t scancode = 0;
|
||||
bool extended = false;
|
||||
bool released = false;
|
||||
|
|
Loading…
Reference in New Issue