218 lines
5.8 KiB
C
218 lines
5.8 KiB
C
/// @file mouse.c
|
|
/// @brief Driver for *PS2* Mouses.
|
|
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
|
|
/// See LICENSE.md for details.is distributed under the MIT License.
|
|
/// @addtogroup mouse
|
|
/// @{
|
|
|
|
// Include the kernel log levels.
|
|
#include "sys/kernel_levels.h"
|
|
/// Change the header.
|
|
#define __DEBUG_HEADER__ "[MOUSE ]"
|
|
/// Set the log level.
|
|
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE
|
|
|
|
#include "drivers/mouse.h"
|
|
#include "descriptor_tables/isr.h"
|
|
#include "hardware/pic8259.h"
|
|
#include "io/port_io.h"
|
|
|
|
/// The mouse starts sending automatic packets.
|
|
#define MOUSE_ENABLE_PACKET 0xF4
|
|
/// The mouse stops sending automatic packets.
|
|
#define MOUSE_DISABLE_PACKET 0xF5
|
|
/// Disables streaming, sets the packet rate to 100 per second, and resolution to 4 pixels per mm.
|
|
#define MOUSE_USE_DEFAULT_SETTINGS 0xF6
|
|
|
|
/// Mouse ISR cycle.
|
|
static uint8_t mouse_cycle = 0;
|
|
/// Mouse communication data.
|
|
static int8_t mouse_bytes[3];
|
|
/// Mouse x position.
|
|
static int32_t mouse_x = (800 / 2);
|
|
/// Mouse y position.
|
|
static int32_t mouse_y = (600 / 2);
|
|
|
|
/// @brief Mouse wait for a command.
|
|
/// @param type 1 for sending - 0 for receiving.
|
|
static void __mouse_waitcmd(unsigned char type)
|
|
{
|
|
register unsigned int _time_out = 100000;
|
|
if (type == 0) {
|
|
// DATA.
|
|
while (_time_out--) {
|
|
if ((inportb(0x64) & 1) == 1) {
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
} else {
|
|
while (_time_out--) // SIGNALS
|
|
{
|
|
if ((inportb(0x64) & 2) == 0) {
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// @brief Send data to mouse.
|
|
/// @param data The data to send.
|
|
static void __mouse_write(unsigned char data)
|
|
{
|
|
__mouse_waitcmd(1);
|
|
outportb(0x64, 0xD4);
|
|
__mouse_waitcmd(1);
|
|
outportb(0x60, data);
|
|
}
|
|
|
|
/// @brief Read data from mouse.
|
|
/// @return The data received from mouse.
|
|
static unsigned char __mouse_read()
|
|
{
|
|
__mouse_waitcmd(0);
|
|
return inportb(0x60);
|
|
}
|
|
|
|
/// @brief The interrupt service routine of the mouse.
|
|
/// @param f The interrupt stack frame.
|
|
static void __mouse_isr(pt_regs *f)
|
|
{
|
|
(void)f;
|
|
// Get the input bytes.
|
|
mouse_bytes[mouse_cycle++] = (char)inportb(0x60);
|
|
if (mouse_cycle == 3) {
|
|
// Reset the mouse cycle.
|
|
mouse_cycle = 0;
|
|
// ----------------------------
|
|
// Get the X coordinates.
|
|
// ----------------------------
|
|
if ((mouse_bytes[0] & 0x40) == 0) {
|
|
// Bit number 4 of the first byte (value 0x10) indicates that
|
|
// delta X (the 2nd byte) is a negative number, if it is set.
|
|
if ((mouse_bytes[0] & 0x10) == 0) {
|
|
mouse_x -= mouse_bytes[1];
|
|
} else {
|
|
mouse_x += mouse_bytes[1];
|
|
}
|
|
} else {
|
|
// Overflow.
|
|
mouse_x += mouse_bytes[1] / 2;
|
|
}
|
|
// ----------------------------
|
|
// Get the Y coordinates.
|
|
// ----------------------------
|
|
if ((mouse_bytes[0] & 0x80) == 0) {
|
|
// Bit number 5 of the first byte (value 0x20) indicates that
|
|
// delta Y (the 3rd byte) is a negative number, if it is set.
|
|
if ((mouse_bytes[0] & 0x20) == 0) {
|
|
mouse_y -= mouse_bytes[2];
|
|
} else {
|
|
mouse_y += mouse_bytes[2];
|
|
}
|
|
} else {
|
|
// Overflow.
|
|
mouse_y -= mouse_bytes[2] / 2;
|
|
}
|
|
// ----------------------------
|
|
// Apply cursor constraint (800x600).
|
|
// ----------------------------
|
|
if (mouse_x <= 0) {
|
|
mouse_x = 0;
|
|
} else if (mouse_x >= (800 - 16)) {
|
|
mouse_x = 800 - 16;
|
|
}
|
|
if (mouse_y <= 0) {
|
|
mouse_y = 0;
|
|
} else if (mouse_y >= (600 - 24)) {
|
|
mouse_y = 600 - 24;
|
|
}
|
|
// Print the position.
|
|
// pr_default("\rX: %d | Y: %d\n", mouse_x, mouse_y);
|
|
|
|
// Move the cursor.
|
|
// video_set_cursor(mouse_x, mouse_y);
|
|
|
|
// Here a problem is detected, if the mouse moves
|
|
// Pressed keys are detected.
|
|
// Detecting keystrokes.
|
|
// Center pressed.
|
|
if ((mouse_bytes[0] & 0x04) == 0) {
|
|
// pr_default(LNG_MOUSE_MID);
|
|
}
|
|
// Right pressed.
|
|
if ((mouse_bytes[0] & 0x02) == 0) {
|
|
// pr_default(LNG_MOUSE_RIGHT);
|
|
}
|
|
// Left pressed.
|
|
if ((mouse_bytes[0] & 0x01) == 0) {
|
|
// pr_default(LNG_MOUSE_LEFT);
|
|
}
|
|
}
|
|
pic8259_send_eoi(IRQ_MOUSE);
|
|
}
|
|
|
|
/// @brief Enable the mouse driver.
|
|
static void __mouse_enable()
|
|
{
|
|
// Enable the mouse interrupts.
|
|
pic8259_irq_enable(IRQ_MOUSE);
|
|
// Disable the mouse.
|
|
__mouse_write(MOUSE_ENABLE_PACKET);
|
|
// Acknowledge.
|
|
__mouse_read();
|
|
}
|
|
|
|
/// @brief Disable the mouse driver.
|
|
static void __mouse_disable()
|
|
{
|
|
// Disable the mouse interrupts.
|
|
pic8259_irq_disable(IRQ_MOUSE);
|
|
// Disable the mouse.
|
|
__mouse_write(MOUSE_DISABLE_PACKET);
|
|
// Acknowledge.
|
|
__mouse_read();
|
|
}
|
|
|
|
int mouse_initialize()
|
|
{
|
|
// Enable the auxiliary mouse device.
|
|
__mouse_waitcmd(1);
|
|
outportb(0x64, 0xA8);
|
|
|
|
// Enable the interrupts.
|
|
__mouse_waitcmd(1);
|
|
outportb(0x64, 0x20);
|
|
__mouse_waitcmd(0);
|
|
uint8_t status_byte = (inportb(0x60) | 2);
|
|
__mouse_waitcmd(1);
|
|
outportb(0x64, 0x60);
|
|
__mouse_waitcmd(1);
|
|
outportb(0x60, status_byte);
|
|
|
|
// Tell the mouse to use default settings.
|
|
__mouse_write(MOUSE_USE_DEFAULT_SETTINGS);
|
|
// Acknowledge.
|
|
__mouse_read();
|
|
|
|
// Setup the mouse handler.
|
|
irq_install_handler(IRQ_MOUSE, __mouse_isr, "mouse");
|
|
|
|
// Enable the mouse.
|
|
__mouse_enable();
|
|
return 0;
|
|
}
|
|
|
|
int mouse_finalize()
|
|
{
|
|
// Uninstall the IRQ.
|
|
irq_uninstall_handler(IRQ_MOUSE, __mouse_isr);
|
|
|
|
// Disable the mouse.
|
|
__mouse_disable();
|
|
return 0;
|
|
}
|
|
|
|
/// @}
|