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/vga.o \
drivers/speaker.o \ drivers/speaker.o \
drivers/timer.o \ drivers/timer.o \
drivers/keyboard.o drivers/keyboard.o \
drivers/mouse.o
# Дефолтное правило (просто сборка бинарника) # Дефолтное правило (просто сборка бинарника)
all: $(TARGET) all: $(TARGET)

View file

@ -15,7 +15,7 @@
- [x] Нормальный драйвер VGA (скролл итд) - [x] Нормальный драйвер VGA (скролл итд)
- [x] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд) - [x] Нормальный драйвер клавиатуры (Caps Lock, Shift, Numpad итд)
- [x] Драйвер PC Speaker - [x] Драйвер PC Speaker
- [ ] Драйвер мыши - [x] Драйвер мыши
## 2. Процессы, память, user mode, еще драйвера ## 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/serial.h"
#include "../drivers/timer.h" #include "../drivers/timer.h"
#include "../drivers/keyboard.h" #include "../drivers/keyboard.h"
#include "../drivers/mouse.h"
// Сам массив IDT на 256 векторов и указатель на него // Сам массив IDT на 256 векторов и указатель на него
struct idt_entry 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(); extern void isr20(); extern void isr21();
// Аппаратные прерывания железа (IRQ) // Аппаратные прерывания железа (IRQ)
extern void irq0(); extern void irq1(); extern void irq0(); extern void irq1(); extern void irq12();
// Внешняя функция на ассемблере для выполнения 'lidt' // Внешняя функция на ассемблере для выполнения 'lidt'
extern void idt_load(); extern void idt_load();
@ -61,6 +62,7 @@ void idt_init(void) {
// Вешаем аппаратные прерывания (после перемапливания PIC они будут тут) // Вешаем аппаратные прерывания (после перемапливания PIC они будут тут)
idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); // Таймер PIT idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); // Таймер PIT
idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); // Клавиатура idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); // Клавиатура
idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); // Мышь PS/2
// Загружаем IDTR в процессор // Загружаем IDTR в процессор
idt_load(); idt_load();
@ -79,6 +81,8 @@ void irq_handler(struct registers regs) {
timer_handler(); timer_handler();
} else if (regs.int_no == 33) { } else if (regs.int_no == 33) {
keyboard_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33 keyboard_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33
} else if (regs.int_no == 44) {
mouse_handler(); // <-- Вызываем обработчик клавиатуры при векторе 33
} else { } else {
char irq_str[4]; char irq_str[4];
itoa(regs.int_no, irq_str, 10); itoa(regs.int_no, irq_str, 10);

View file

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

View file

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