diff --git a/Kernel/Devices/PS2MouseDevice.cpp b/Kernel/Devices/PS2MouseDevice.cpp index 0af6ca40104..c7d8ff54f55 100644 --- a/Kernel/Devices/PS2MouseDevice.cpp +++ b/Kernel/Devices/PS2MouseDevice.cpp @@ -10,6 +10,11 @@ #define I8042_MOUSE_BUFFER 0x20 #define I8042_KEYBOARD_BUFFER 0x00 +#define PS2MOUSE_GET_DEVICE_ID 0xF2 +#define PS2MOUSE_SET_SAMPLE_RATE 0xF3 + +#define PS2MOUSE_INTELLIMOUSE_ID 0x03 + //#define PS2MOUSE_DEBUG static PS2MouseDevice* s_the; @@ -40,6 +45,21 @@ void PS2MouseDevice::handle_irq() byte data = IO::in8(I8042_BUFFER); m_data[m_data_state] = data; + + auto commit_packet = [&] { + m_data_state = 0; +#ifdef PS2MOUSE_DEBUG + dbgprintf("PS2Mouse: %d, %d %s %s (buffered: %u)\n", + m_data[1], + m_data[2], + (m_data[0] & 1) ? "Left" : "", + (m_data[0] & 2) ? "Right" : "", + m_queue.size() + ); +#endif + parse_data_packet(); + }; + switch (m_data_state) { case 0: if (!(data & 0x08)) { @@ -52,17 +72,15 @@ void PS2MouseDevice::handle_irq() ++m_data_state; break; case 2: - m_data_state = 0; -#ifdef PS2MOUSE_DEBUG - dbgprintf("PS2Mouse: %d, %d %s %s (buffered: %u)\n", - m_data[1], - m_data[2], - (m_data[0] & 1) ? "Left" : "", - (m_data[0] & 2) ? "Right" : "", - m_queue.size() - ); -#endif - parse_data_packet(); + if (m_has_wheel) { + ++m_data_state; + break; + } + commit_packet(); + break; + case 3: + ASSERT(m_has_wheel); + commit_packet(); break; } } @@ -72,6 +90,9 @@ void PS2MouseDevice::parse_data_packet() { int x = m_data[1]; int y = m_data[2]; + int z = 0; + if (m_has_wheel) + z = (char)m_data[3]; bool x_overflow = m_data[0] & 0x40; bool y_overflow = m_data[0] & 0x80; bool x_sign = m_data[0] & 0x10; @@ -87,7 +108,9 @@ void PS2MouseDevice::parse_data_packet() MousePacket packet; packet.dx = x; packet.dy = y; + packet.dz = z; packet.buttons = m_data[0] & 0x07; + m_queue.enqueue(packet); } @@ -119,17 +142,52 @@ void PS2MouseDevice::initialize() // Set default settings. mouse_write(0xf6); - byte ack1 = mouse_read(); - ASSERT(ack1 == 0xfa); + expect_ack(); // Enable. mouse_write(0xf4); - byte ack2 = mouse_read(); - ASSERT(ack2 == 0xfa); + expect_ack(); + + mouse_write(PS2MOUSE_GET_DEVICE_ID); + expect_ack(); + byte device_id = mouse_read(); + + if (device_id != PS2MOUSE_INTELLIMOUSE_ID) { + // Send magical wheel initiation sequence. + mouse_write(PS2MOUSE_SET_SAMPLE_RATE); + expect_ack(); + mouse_write(200); + expect_ack(); + mouse_write(PS2MOUSE_SET_SAMPLE_RATE); + expect_ack(); + mouse_write(100); + expect_ack(); + mouse_write(PS2MOUSE_SET_SAMPLE_RATE); + expect_ack(); + mouse_write(80); + expect_ack(); + + mouse_write(PS2MOUSE_GET_DEVICE_ID); + expect_ack(); + device_id = mouse_read(); + } + + if (device_id == PS2MOUSE_INTELLIMOUSE_ID) { + m_has_wheel = true; + kprintf("PS2MouseDevice: Mouse wheel enabled!\n"); + } else { + kprintf("PS2MouseDevice: No mouse wheel detected!\n"); + } enable_irq(); } +void PS2MouseDevice::expect_ack() +{ + byte data = mouse_read(); + ASSERT(data == I8042_ACK); +} + void PS2MouseDevice::prepare_for_input() { for (;;) { diff --git a/Kernel/Devices/PS2MouseDevice.h b/Kernel/Devices/PS2MouseDevice.h index a3e4eef698a..6a04ab672c7 100644 --- a/Kernel/Devices/PS2MouseDevice.h +++ b/Kernel/Devices/PS2MouseDevice.h @@ -33,8 +33,10 @@ private: void wait_then_write(byte port, byte data); byte wait_then_read(byte port); void parse_data_packet(); + void expect_ack(); CircularQueue m_queue; byte m_data_state { 0 }; - byte m_data[3]; + byte m_data[4]; + bool m_has_wheel { false }; }; diff --git a/Kernel/MousePacket.h b/Kernel/MousePacket.h index ad0513ff35e..26d03f49887 100644 --- a/Kernel/MousePacket.h +++ b/Kernel/MousePacket.h @@ -3,5 +3,6 @@ struct MousePacket { int dx { 0 }; int dy { 0 }; - byte buttons; + int dz { 0 }; + byte buttons { 0 }; };