From 2a7e3f00256e20d9abcc059a0d666968c0280611 Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Sat, 6 Aug 2016 22:13:26 +0200 Subject: [PATCH] Implement a PS/2 mouse driver --- kernel/include/mouse.hpp | 22 +++++++ kernel/src/kernel.cpp | 2 + kernel/src/mouse.cpp | 122 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 kernel/include/mouse.hpp create mode 100644 kernel/src/mouse.cpp diff --git a/kernel/include/mouse.hpp b/kernel/include/mouse.hpp new file mode 100644 index 00000000..9599839a --- /dev/null +++ b/kernel/include/mouse.hpp @@ -0,0 +1,22 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#ifndef MOUSE_HPP +#define MOUSE_HPP + +#include + +namespace mouse { + +void install(); + +uint64_t x(); +uint64_t y(); + +} //end of namespace mouse + +#endif diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index f31814d9..0a5975da 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -12,6 +12,7 @@ #include "kalloc.hpp" #include "timer.hpp" #include "keyboard.hpp" +#include "mouse.hpp" #include "serial.hpp" #include "disks.hpp" #include "pci.hpp" @@ -106,6 +107,7 @@ void kernel_main(){ //Install drivers timer::install(); keyboard::install_driver(); + mouse::install(); disks::detect_disks(); pci::detect_devices(); network::init(); diff --git a/kernel/src/mouse.cpp b/kernel/src/mouse.cpp new file mode 100644 index 00000000..f3eb7e05 --- /dev/null +++ b/kernel/src/mouse.cpp @@ -0,0 +1,122 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#include + +#include "mouse.hpp" +#include "interrupts.hpp" +#include "kernel_utils.hpp" +#include "logging.hpp" +#include "vesa.hpp" + +namespace { + +constexpr const uint16_t DATA_PORT = 0x60; +constexpr const uint16_t STATUS_PORT = 0x64; + +uint8_t cycle = 0; // The interrupt cycles through different information + +uint8_t mouse_packet[3]; +uint16_t position_x = 0; +uint16_t position_y = 0; + +void mouse_handler(interrupt::syscall_regs*, void*){ + mouse_packet[cycle++] = in_byte(DATA_PORT); + + if(cycle == 3){ + cycle = 0; + + auto state = mouse_packet[0]; + + // Discard overflow packets + if(state & ((1 << 6) | (1 << 7))){ + return; + } + + // Compute the 9bit delta values + int16_t delta_x = mouse_packet[1] - ((state << 4) & 0x100); + int16_t delta_y = mouse_packet[2] - ((state << 3) & 0x100); + + // Reverse the y direction + delta_y = -delta_y; + + position_x = std::max(int16_t(position_x) + delta_x, 0); + position_y = std::max(int16_t(position_y) + delta_y, 0); + + if(vesa::enabled()){ + position_x = std::min(position_x, uint16_t(vesa::width())); + position_y = std::min(position_y, uint16_t(vesa::height())); + } + + logging::logf(logging::log_level::TRACE, "mouse: interrupt %d:%d \n", int64_t(position_x), int64_t(position_y)); + } +} + +void ps2_data_wait(){ + auto timeout = 100000; + while(timeout-- && (in_byte(STATUS_PORT) & 1) != 1){} +} + +void ps2_signal_wait(){ + auto timeout = 100000; + while(timeout-- && (in_byte(STATUS_PORT) & 2) != 0){} +} + +void ps2_mouse_write(uint8_t value){ + // Send a command + ps2_signal_wait(); + out_byte(STATUS_PORT, 0xD4); + + // Send the data + ps2_signal_wait(); + out_byte(DATA_PORT, value); +} + +uint8_t ps2_mouse_read(){ + ps2_data_wait(); + return in_byte(DATA_PORT); +} + +} //end of anonymous namespace + +void mouse::install(){ + if(!interrupt::register_irq_handler(12, mouse_handler, nullptr)){ + logging::logf(logging::log_level::ERROR, "mouse: Unable to register IRQ handler 12\n"); + return; + } + + // Enable the mouse auxiliary device + ps2_signal_wait(); + out_byte(STATUS_PORT, 0xA8); + + // Enable interrupts + ps2_signal_wait(); + out_byte(STATUS_PORT, 0x20); + auto status = ps2_mouse_read() | 2; + ps2_signal_wait(); + out_byte(STATUS_PORT, 0x60); + ps2_signal_wait(); + out_byte(DATA_PORT, status); + + // Use default settings + ps2_mouse_write(0xF6); + ps2_mouse_read(); + + // Enable the mouse + ps2_mouse_write(0xF4); + ps2_mouse_read(); + + logging::logf(logging::log_level::TRACE, "mouse: PS/2 mouse driver installed\n"); +} + +uint64_t mouse::x(){ + return position_x; +} + +uint64_t mouse::y(){ + return position_y; +}