serenity/Kernel/PS2MouseDevice.cpp
Andreas Kling fd4e86460b Make PS2MouseDevice behave more like a proper character device.
Get rid of the goofy MouseClient interface and have the GUI event loop just
read mouse data from the character device.

The previous approach was awful as it was sending us into random GUI code
in the mouse interrupt handler.
2019-01-12 05:23:16 +01:00

133 lines
2.3 KiB
C++

#include "PS2MouseDevice.h"
#include "IO.h"
//#define PS2MOUSE_DEBUG
static PS2MouseDevice* s_the;
PS2MouseDevice::PS2MouseDevice()
: IRQHandler(12)
, CharacterDevice(10, 1)
{
s_the = this;
initialize();
}
PS2MouseDevice::~PS2MouseDevice()
{
}
PS2MouseDevice& PS2MouseDevice::the()
{
return *s_the;
}
void PS2MouseDevice::handle_irq()
{
byte data = IO::in8(0x60);
m_data[m_data_state] = data;
switch (m_data_state) {
case 0:
ASSERT(data & 0x08);
++m_data_state;
break;
case 1:
++m_data_state;
break;
case 2:
m_data_state = 0;
#ifdef PS2MOUSE_DEBUG
dbgprintf("PS2Mouse: %d, %d %s %s\n",
m_data[1],
m_data[2],
(m_data[0] & 1) ? "Left" : "",
(m_data[0] & 2) ? "Right" : ""
);
#endif
m_buffer.write((const byte*)m_data, 3);
break;
}
}
void PS2MouseDevice::wait_then_write(byte port, byte data)
{
prepare_for_output();
IO::out8(port, data);
}
byte PS2MouseDevice::wait_then_read(byte port)
{
prepare_for_input();
return IO::in8(port);
}
void PS2MouseDevice::initialize()
{
// Enable PS aux port
wait_then_write(0x64, 0xa8);
// Enable interrupts
wait_then_write(0x64, 0x20);
byte status = wait_then_read(0x60) | 2;
wait_then_write(0x64, 0x60);
wait_then_write(0x60, status);
// Set default settings.
mouse_write(0xf6);
byte ack1 = mouse_read();
ASSERT(ack1 == 0xfa);
// Enable.
mouse_write(0xf4);
byte ack2 = mouse_read();
ASSERT(ack2 == 0xfa);
enable_irq();
}
void PS2MouseDevice::prepare_for_input()
{
for (;;) {
if (IO::in8(0x64) & 1)
return;
}
}
void PS2MouseDevice::prepare_for_output()
{
for (;;) {
if (!(IO::in8(0x64) & 2))
return;
}
}
void PS2MouseDevice::mouse_write(byte data)
{
prepare_for_output();
IO::out8(0x64, 0xd4);
prepare_for_output();
IO::out8(0x60, data);
}
byte PS2MouseDevice::mouse_read()
{
prepare_for_input();
return IO::in8(0x60);
}
bool PS2MouseDevice::has_data_available_for_reading() const
{
return !m_buffer.is_empty();
}
ssize_t PS2MouseDevice::read(byte* buffer, size_t size)
{
return m_buffer.read(buffer, size);
}
ssize_t PS2MouseDevice::write(const byte*, size_t)
{
return 0;
}