MOUSE: добавлена поддержка (в UART)

This commit is contained in:
msh356 2026-07-03 12:26:04 +03:00
parent ef565c6afb
commit a66b0416d5
7 changed files with 150 additions and 4 deletions

View file

@ -25,7 +25,8 @@ OBJ = boot/boot.o \
drivers/vga.o \
drivers/speaker.o \
drivers/timer.o \
drivers/keyboard.o
drivers/keyboard.o \
drivers/mouse.o
# Дефолтное правило (просто сборка бинарника)
all: $(TARGET)

View file

@ -15,7 +15,7 @@
- [x] Нормальный драйвер VGA (скролл итд)
- [x] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд)
- [x] Драйвер PC Speaker
- [ ] Драйвер мыши
- [x] Драйвер мыши
## 2. Процессы, память, user mode, еще драйвера

123
drivers/mouse.c Normal file
View file

@ -0,0 +1,123 @@
#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");
}
}

9
drivers/mouse.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef MOUSE_H
#define MOUSE_H
#include <stdint.h>
void mouse_init(void);
void mouse_handler(void);
#endif

View file

@ -3,6 +3,7 @@
#include "../drivers/serial.h"
#include "../drivers/timer.h"
#include "../drivers/keyboard.h"
#include "../drivers/mouse.h"
// Сам массив IDT на 256 векторов и указатель на него
struct idt_entry idt[256];
@ -17,7 +18,7 @@ extern void isr16(); extern void isr17(); extern void isr18(); extern void isr19
extern void isr20(); extern void isr21();
// Аппаратные прерывания железа (IRQ)
extern void irq0(); extern void irq1();
extern void irq0(); extern void irq1(); extern void irq12();
// Внешняя функция на ассемблере для выполнения 'lidt'
extern void idt_load();
@ -61,6 +62,7 @@ void idt_init(void) {
// Вешаем аппаратные прерывания (после перемапливания PIC они будут тут)
idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); // Таймер PIT
idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); // Клавиатура
idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); // Мышь PS/2
// Загружаем IDTR в процессор
idt_load();
@ -79,6 +81,8 @@ void irq_handler(struct registers regs) {
timer_handler();
} else if (regs.int_no == 33) {
keyboard_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33
} else if (regs.int_no == 44) {
mouse_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33
} else {
char irq_str[4];
itoa(regs.int_no, irq_str, 10);

View file

@ -4,7 +4,7 @@ bits 32
global idt_load
global isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8, isr9, isr10
global isr11, isr12, isr13, isr14, isr15, isr16, isr17, isr18, isr19, isr20, isr21
global irq0, irq1
global irq0, irq1, irq12
; Импортируем Си-обработчики
extern idtp
@ -66,6 +66,7 @@ ISR_ERRCODE 21
IRQ 32, 0 ; IRQ0 - Таймер
IRQ 33, 1 ; IRQ1 - Клавиатура
IRQ 44, 12 ; IRQ12 - Мышь (вектор 44)
; Перенаправляем глобальные имена на сгенерированные макросами точки
isr0: jmp idt_stub_isr_0
@ -93,6 +94,7 @@ isr21: jmp idt_stub_isr_21
irq0: jmp idt_stub_irq_0
irq1: jmp idt_stub_irq_1
irq12: jmp idt_stub_irq_12 ; <-- Сюда процессор прыгнет при векторе 44
; Общая точка сборки для Исключений Процессора
isr_common_stub:

View file

@ -1,5 +1,6 @@
#include "../drivers/vga.h"
#include "../drivers/serial.h"
#include "../drivers/mouse.h"
#include "../drivers/timer.h"
#include "../drivers/speaker.h"
#include "gdt.h"
@ -24,8 +25,14 @@ void kernel_main(void) {
pic_clear_mask(0);
log_info(LOG_NORMAL, "Unmasking IRQ 1... (keyboard)");
pic_clear_mask(1);
log_info(LOG_NORMAL, "Unmasking IRQ 2... (slave pic)");
pic_clear_mask(2);
log_info(LOG_NORMAL, "Unmasking IRQ 12... (mouse)");
pic_clear_mask(12);
log_info(LOG_NORMAL, "Registering timer at 100Hz");
timer_init(100);
log_info(LOG_NORMAL, "Registering mouse");
mouse_init();
log_info(LOG_NORMAL, "Enabling IRQ...");
__asm__ __volatile__("sti");
vga_set_color(VGA_COLOR_LIGHT_GREEN, VGA_COLOR_BLACK);