123 lines
3.7 KiB
C
123 lines
3.7 KiB
C
#include "mouse.h"
|
||
#include "../kernel/io.h"
|
||
#include "../kernel/string.h"
|
||
#include "../drivers/serial.h" // Для kprint_serial
|
||
|
||
#define PS2_DATA 0x60
|
||
#define PS2_STATUS 0x64
|
||
#define PS2_COMMAND 0x64
|
||
|
||
static void ps2_wait_write(void) {
|
||
while (inb(PS2_STATUS) & 0x02);
|
||
}
|
||
|
||
static void ps2_wait_read(void) {
|
||
while (!(inb(PS2_STATUS) & 0x01));
|
||
}
|
||
|
||
static void mouse_write(uint8_t data) {
|
||
ps2_wait_write();
|
||
outb(PS2_COMMAND, 0xD4); // Сигнал: шлем команду именно мыши
|
||
ps2_wait_write();
|
||
outb(PS2_DATA, data);
|
||
}
|
||
|
||
static uint8_t mouse_read(void) {
|
||
ps2_wait_read();
|
||
return inb(PS2_DATA);
|
||
}
|
||
|
||
void mouse_init(void) {
|
||
uint8_t status;
|
||
|
||
kprint_serial("Initializing PS/2 Mouse...\n");
|
||
|
||
// Включаем второй порт PS/2 (мышь)
|
||
ps2_wait_write();
|
||
outb(PS2_COMMAND, 0xA8);
|
||
io_wait();
|
||
|
||
// Читаем Command Byte, чтобы включить прерывания
|
||
ps2_wait_write();
|
||
outb(PS2_COMMAND, 0x20);
|
||
ps2_wait_read();
|
||
status = inb(PS2_DATA) | 2; // Бит 1 — прерывания IRQ12 от мыши
|
||
status &= ~0x20; // Сбрасываем Бит 5 — активируем Mouse Clock
|
||
|
||
// Записываем Command Byte обратно
|
||
ps2_wait_write();
|
||
outb(PS2_COMMAND, 0x60);
|
||
ps2_wait_write();
|
||
outb(PS2_DATA, status);
|
||
|
||
// Настраиваем саму мышь
|
||
mouse_write(0xF6); // Загрузить дефолтные параметры
|
||
mouse_read(); // Читаем ACK (0xFA)
|
||
|
||
mouse_write(0xF4); // Включаем передачу пакетов (Data Reporting)
|
||
mouse_read(); // Читаем ACK (0xFA)
|
||
|
||
kprint_serial("Mouse initialized successfully.\n");
|
||
}
|
||
|
||
static uint8_t mouse_cycle = 0;
|
||
static uint8_t mouse_packet[3];
|
||
static int mouse_x = 40; // Стартуем по центру текстового экрана 80x25
|
||
static int mouse_y = 12;
|
||
|
||
void mouse_handler(void) {
|
||
uint8_t status = inb(PS2_STATUS);
|
||
|
||
// Проверяем, что в буфере реально есть данные и они от мыши (бит 5 выставлен)
|
||
if (!(status & 0x01) || !(status & 0x20)) {
|
||
return;
|
||
}
|
||
|
||
mouse_packet[mouse_cycle++] = inb(PS2_DATA);
|
||
|
||
if (mouse_cycle == 3) {
|
||
mouse_cycle = 0;
|
||
|
||
// Бит 3 первого байта всегда должен быть равен 1 (проверка синхронизации)
|
||
if (!(mouse_packet[0] & 0x08)) {
|
||
return;
|
||
}
|
||
|
||
uint8_t flags = mouse_packet[0];
|
||
int offset_x = (int)mouse_packet[1];
|
||
int offset_y = (int)mouse_packet[2];
|
||
|
||
// Обработка знаков смещения (8 бит -> 32 бита с сохранением знака)
|
||
if (flags & 0x10) offset_x |= 0xFFFFFF00;
|
||
if (flags & 0x20) offset_y |= 0xFFFFFF00;
|
||
|
||
mouse_x += offset_x;
|
||
mouse_y -= offset_y; // Инвертируем Y, так как в VGA координатах 0 верх
|
||
|
||
// Ограничиваем рамками консоли 80x25
|
||
if (mouse_x < 0) mouse_x = 0;
|
||
if (mouse_x >= 80) mouse_x = 79;
|
||
if (mouse_y < 0) mouse_y = 0;
|
||
if (mouse_y >= 25) mouse_y = 24;
|
||
|
||
// Чек кнопок
|
||
int left_click = flags & 0x01;
|
||
int right_click = flags & 0x02;
|
||
|
||
// Выводим инфу в UART через itoa
|
||
char buf[16];
|
||
|
||
kprint_serial("Mouse: X=");
|
||
itoa(mouse_x, buf, 10);
|
||
kprint_serial(buf);
|
||
|
||
kprint_serial(" Y=");
|
||
itoa(mouse_y, buf, 10);
|
||
kprint_serial(buf);
|
||
|
||
if (left_click) kprint_serial(" [LEFT]");
|
||
if (right_click) kprint_serial(" [RIGHT]");
|
||
|
||
kprint_serial("\n");
|
||
}
|
||
}
|