mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 21:27:45 +00:00
Kernel: Untie PS2 mouse and keyboard devices from i8042 implementation
To ensure actual PS2 code is not tied to the i8042 code, we make them separated in the following ways: - PS2KeyboardDevice and PS2MouseDevice classes are no longer inheriting from the IRQHandler class. Instead we have specific IRQHandler derived class for the i8042 controller implementation, which is used to ensure that we don't end up mixing PS2 code with low-level interrupt handling functionality. In the future this means that we could add a driver for other PS2 controllers that might have only one interrupt handler but multiple PS2 devices are attached, therefore, making it easier to put the right propagation flow from the controller driver all the way to the HID core code. - A simple abstraction layer is added between the PS2 command set which devices could use and the actual implementation low-level commands. This means that the code in PS2MouseDevice and PS2KeyboardDevice classes is no longer tied to i8042 implementation-specific commands, so now these objects could send PS2 commands to their PS2 controller and get a PS2Response which abstracts the given response too.
This commit is contained in:
parent
d276cac82c
commit
89a8920764
13 changed files with 392 additions and 272 deletions
|
@ -8,9 +8,9 @@
|
|||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Bus/SerialIO/Controller.h>
|
||||
#include <Kernel/Devices/HID/Controller.h>
|
||||
#include <Kernel/Devices/HID/KeyboardDevice.h>
|
||||
#include <Kernel/Devices/HID/MouseDevice.h>
|
||||
#include <Kernel/Bus/SerialIO/Device.h>
|
||||
#include <Kernel/Bus/SerialIO/PS2Definitions.h>
|
||||
#include <Kernel/Interrupts/IRQHandler.h>
|
||||
#include <Kernel/Locking/Spinlock.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -67,35 +67,25 @@ enum I8042Response : u8 {
|
|||
Resend = 0xFE,
|
||||
};
|
||||
|
||||
class I8042Controller;
|
||||
class PS2KeyboardDevice;
|
||||
class PS2MouseDevice;
|
||||
class PS2Device {
|
||||
|
||||
class I8042Controller;
|
||||
class I8042ControllerIRQHandler final
|
||||
: public IRQHandler {
|
||||
public:
|
||||
virtual ~PS2Device() = default;
|
||||
static ErrorOr<NonnullOwnPtr<I8042ControllerIRQHandler>> try_create(I8042Controller const&, u8 irq_number);
|
||||
|
||||
virtual void irq_handle_byte_read(u8 byte) = 0;
|
||||
virtual void enable_interrupts() = 0;
|
||||
private:
|
||||
I8042ControllerIRQHandler(I8042Controller const& controller, u8 irq_number);
|
||||
|
||||
enum class Type {
|
||||
Unknown = 0,
|
||||
Keyboard,
|
||||
Mouse,
|
||||
};
|
||||
// ^IRQHandler
|
||||
virtual bool handle_irq(RegisterState const&) override;
|
||||
virtual StringView purpose() const override { return "I8042ControllerIRQHandler"sv; }
|
||||
|
||||
virtual Type instrument_type() const = 0;
|
||||
|
||||
protected:
|
||||
explicit PS2Device(I8042Controller const& ps2_controller)
|
||||
: m_i8042_controller(ps2_controller)
|
||||
{
|
||||
}
|
||||
|
||||
NonnullRefPtr<I8042Controller> const m_i8042_controller;
|
||||
NonnullRefPtr<I8042Controller> const m_controller;
|
||||
};
|
||||
|
||||
class PS2KeyboardDevice;
|
||||
class PS2MouseDevice;
|
||||
class HIDManagement;
|
||||
class I8042Controller final : public SerialIOController {
|
||||
friend class PS2KeyboardDevice;
|
||||
|
@ -105,59 +95,47 @@ public:
|
|||
static ErrorOr<NonnullRefPtr<I8042Controller>> create();
|
||||
|
||||
ErrorOr<void> detect_devices();
|
||||
virtual ErrorOr<void> send_command(PortIndex, DeviceCommand command) override;
|
||||
virtual ErrorOr<void> send_command(PortIndex, DeviceCommand command, u8 data) override;
|
||||
|
||||
ErrorOr<void> reset_device(PS2Device::Type device)
|
||||
virtual ErrorOr<void> reset_device(PortIndex port_index) override
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_reset_device(device);
|
||||
return do_reset_device(port_index);
|
||||
}
|
||||
|
||||
ErrorOr<u8> send_command(PS2Device::Type device, u8 command)
|
||||
virtual ErrorOr<u8> read_from_device(PortIndex port_index) override
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_send_command(device, command);
|
||||
return do_read_from_device(port_index);
|
||||
}
|
||||
ErrorOr<u8> send_command(PS2Device::Type device, u8 command, u8 data)
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_send_command(device, command, data);
|
||||
}
|
||||
|
||||
ErrorOr<u8> read_from_device(PS2Device::Type device)
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_read_from_device(device);
|
||||
}
|
||||
|
||||
ErrorOr<void> wait_then_write(u8 port, u8 data)
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_wait_then_write(port, data);
|
||||
}
|
||||
|
||||
ErrorOr<u8> wait_then_read(u8 port)
|
||||
{
|
||||
SpinlockLocker lock(m_lock);
|
||||
return do_wait_then_read(port);
|
||||
}
|
||||
|
||||
ErrorOr<void> prepare_for_output();
|
||||
ErrorOr<void> prepare_for_input(PS2Device::Type);
|
||||
|
||||
bool irq_process_input_buffer(PS2Device::Type);
|
||||
virtual ErrorOr<void> prepare_for_input(PortIndex) override;
|
||||
|
||||
// Note: This function exists only for the initialization process of the controller
|
||||
bool check_existence_via_probing(Badge<HIDManagement>);
|
||||
|
||||
bool handle_irq(Badge<I8042ControllerIRQHandler>, u8 irq_number);
|
||||
|
||||
private:
|
||||
I8042Controller();
|
||||
ErrorOr<void> do_reset_device(PS2Device::Type);
|
||||
ErrorOr<u8> do_send_command(PS2Device::Type type, u8 data);
|
||||
ErrorOr<u8> do_send_command(PS2Device::Type device, u8 command, u8 data);
|
||||
ErrorOr<u8> do_write_to_device(PS2Device::Type device, u8 data);
|
||||
ErrorOr<u8> do_read_from_device(PS2Device::Type device);
|
||||
|
||||
bool irq_process_input_buffer(PortIndex);
|
||||
|
||||
ErrorOr<void> prepare_for_any_output();
|
||||
|
||||
ErrorOr<void> prepare_for_any_input();
|
||||
|
||||
ErrorOr<void> do_reset_device(PortIndex);
|
||||
ErrorOr<void> do_send_command(PortIndex port_index, u8 data);
|
||||
ErrorOr<void> do_send_command(PortIndex port_index, u8 command, u8 data);
|
||||
ErrorOr<void> do_write_to_device(PortIndex port_index, u8 data);
|
||||
ErrorOr<u8> do_read_from_device(PortIndex port_index);
|
||||
ErrorOr<void> do_wait_then_write(u8 port, u8 data);
|
||||
ErrorOr<u8> do_wait_then_read(u8 port);
|
||||
|
||||
// NOTE: The meaning of "any input" here is that this is not attached
|
||||
// to any PS2 port, but rather we accept any serial input, which is vital
|
||||
// when reading values before initializing any actual PS2 device!
|
||||
ErrorOr<u8> do_wait_then_read_any_input(u8 port);
|
||||
|
||||
ErrorOr<void> drain_output_buffer();
|
||||
|
||||
// Note: These functions exist only for the initialization process of the controller
|
||||
|
@ -169,6 +147,11 @@ private:
|
|||
bool m_second_port_available { false };
|
||||
bool m_is_dual_channel { false };
|
||||
|
||||
enum I8042PortIndex {
|
||||
FirstPort = 0,
|
||||
SecondPort = 1,
|
||||
};
|
||||
|
||||
// NOTE: Each i8042 controller can have at most 2 ports - a regular (traditional
|
||||
// ATKBD) port and AUX port (for mouse devices mostly).
|
||||
// However, the specification for i8042 controller, as well as decent hardware
|
||||
|
@ -180,10 +163,10 @@ private:
|
|||
// cannot be sanely enabled due to obvious peripheral devices' protocol differences, and will result
|
||||
// in misproper data being sent back.
|
||||
struct PS2Port {
|
||||
OwnPtr<PS2Device> device;
|
||||
OwnPtr<SerialIODevice> device;
|
||||
// NOTE: This value is being used as 1:1 map between the I8042 port being handled, to
|
||||
// the either the MouseDevice or KeyboardDevice being attached.
|
||||
Optional<PS2Device::Type> device_type;
|
||||
Optional<PS2DeviceType> device_type;
|
||||
};
|
||||
|
||||
// NOTE: Each i8042 controller can have at most 2 devices - a mouse and keyboard,
|
||||
|
@ -192,6 +175,8 @@ private:
|
|||
PS2Port m_first_ps2_port;
|
||||
// NOTE: This is usually used as the AUX port.
|
||||
PS2Port m_second_ps2_port;
|
||||
|
||||
Array<OwnPtr<I8042ControllerIRQHandler>, 2> m_irq_handlers;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue