-
Notifications
You must be signed in to change notification settings - Fork 0
/
mouse.c
176 lines (138 loc) · 5.1 KB
/
mouse.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stddef.h>
#include <stdint.h>
#include "mouse.h"
#include "acpi.h"
#include "ports.h"
#include "ps2.h"
#include "idt.h"
#include "sys.h"
#include "shell.h"
#include "terminal.h"
#include "clib/stdio.h"
// Funkcje statyczne
static uint8_t mouse_get_id_byte(void);
static void mouse_init_scroll_wheel(void);
static void mouse_init_extra_buttons(void);
static void mouse_set_sample_rate(uint8_t rate);
static void mouse_send_data(uint8_t data);
static void mouse_command_mouseinfo(const char* tokens, uint32_t tokens_count);
// Aktualny stan myszki
// Na starcie zakładam pozycje (0,0) W wyniku tego może być ona potem ujemna
struct mouse_t mouse_info = {0};
// Inicjuje mysz
void mouse_initialize(void)
{
asm("cli");
// Wyłączamy urządzenia, żeby nie przeszkadzały w konfiguracji
ps2_write_command(COMMAND_DISABLE_FIRST_PORT);
ps2_write_command(COMMAND_DISABLE_SECOND_PORT);
// Włączenie przerwania myszy
uint8_t config_byte = ps2_get_config_byte();
config_byte |= CONFIG_SECOND_PORT_INTERRUPT;
ps2_set_config_byte(config_byte);
// Włączenie dodatkowych przycisków
mouse_init_scroll_wheel();
if(mouse_get_id_byte() != MOUSE_ID_WHEEL) report_error("Unable To Init Scroll Wheel");
mouse_init_extra_buttons();
if(mouse_get_id_byte() != MOUSE_ID_EXTRA_BUTTONS) report_error("Unable To Init Extra Buttons");
// Włączenie automatycznej transmisji pakietów
mouse_send_data(COMMAND_MOUSE_ENABLE_STREAMING);
// Wykonanie testu myszy
ps2_write_command(COMMAND_TEST_SECOND_PORT);
uint8_t test_result = ps2_read_data();
if(test_result == DEVICE_TEST_PASSED) printf("PS2 Mouse Test Passed\n");
else report_error("PS2 Mouse Test Failed\n");
// Włączenie urządzeń po skończeniu konfiguracji
ps2_write_command(COMMAND_ENABLE_FIRST_PORT);
ps2_write_command(COMMAND_ENABLE_SECOND_PORT);
asm("sti");
interrupt_register(44, mouse_interrupt_handler);
register_command("mouseinfo", "Display information about mouse position and buttons", mouse_command_mouseinfo);
debug_display_mouse();
}
// Funkcja obsługująca przerwanie myszy
void mouse_interrupt_handler(void)
{
// Nie wiem czemu, ale każda akcja myszki generuje dwa przerwania, tylko pierwsze jest poprawne
// Nie udało mi się znaleść przyczyny powstawania fałszywego przerwania, więc musze je teraz przefiltrować
uint8_t status = inportb(PS2_COMMAND_PORT);
if(!(status & STATUS_MOUSE_DATA_AVAILABLE)) return;
// Ignorowanie błędnych pakietów
if(status & BYTE1_Y_OVERFLOW || status & BYTE1_X_OVERFLOW) return;
// Pobranie paczki z portu
uint32_t b1 = inportb(PS2_DATA_PORT);
uint32_t b2 = inportb(PS2_DATA_PORT);
uint32_t b3 = inportb(PS2_DATA_PORT);
uint32_t b4 = inportb(PS2_DATA_PORT);
// Poprawka na wartości ujemne
if(b1 & BYTE1_X_SIGN) b2 = b2 | 0xFFFFFF00;
if(b1 & BYTE1_Y_SIGN) b3 = b3 | 0xFFFFFF00;
// Aktualizacja stanu myszki
mouse_info.posx += b2;
mouse_info.posy += b3;
if(b1 & BYTE1_LEFT_BTN) mouse_info.left_button = 1;
else mouse_info.left_button = 0;
if(b1 & BYTE1_MIDDLE_BTN) mouse_info.middle_button = 1;
else mouse_info.middle_button = 0;
if(b1 & BYTE1_RIGHT_BTN) mouse_info.right_button = 1;
else mouse_info.right_button = 0;
if(b4 & BYTE4_EXTRA_BUTTON1) mouse_info.extra_button1 = 1;
else mouse_info.extra_button1 = 0;
if(b4 & BYTE4_EXTRA_BUTTON2) mouse_info.extra_button2 = 1;
else mouse_info.extra_button2 = 0;
uint32_t wheel = b4 & BYTE4_Z_MOVEMENT;
if(wheel == 15) mouse_info.scroll_wheel--;
else if(wheel == WHEEL_SCROLL_UP) mouse_info.scroll_wheel++;
}
// Wyświetla aktualny stan myszki
void debug_display_mouse(void)
{
terminal_setcolor(VGA_COLOR_WHITE);
printf("L: %d | R: %d | M: %d | E1: %d | E2: %d\n", mouse_info.left_button, mouse_info.right_button, mouse_info.middle_button, mouse_info.extra_button1, mouse_info.extra_button2);
printf("Pos X: %d\n", mouse_info.posx);
printf("Pos Y: %d\n", mouse_info.posy);
printf("Pos Z: %d\n\n", mouse_info.scroll_wheel);
}
// Zwraca strukture informacji o myszce
struct mouse_t *get_mouse_info(void)
{
return &mouse_info;
}
// Zwraca aktualne ID myszki
static uint8_t mouse_get_id_byte(void)
{
mouse_send_data(COMMAND_MOUSE_GET_ID);
return ps2_read_data();
}
// Aktywuje kółko myszki
static void mouse_init_scroll_wheel(void)
{
mouse_set_sample_rate(200);
mouse_set_sample_rate(100);
mouse_set_sample_rate(80);
}
// Aktywuje dodatkowe przycisi
static void mouse_init_extra_buttons(void)
{
mouse_set_sample_rate(200);
mouse_set_sample_rate(200);
mouse_set_sample_rate(80);
}
// Ustala częstotliwość wystyłania paczek
static void mouse_set_sample_rate(uint8_t rate)
{
mouse_send_data(COMMAND_MOUSE_SET_SAMPLE_RATE);
mouse_send_data(rate);
}
// Wysyła dane do myszy
static void mouse_send_data(uint8_t data)
{
ps2_write_command(COMMAND_MOUSE_PREFIX);
ps2_write_data(data);
ps2_read_data();
}
// Komenda mouseinfo
static void mouse_command_mouseinfo(const char* tokens, uint32_t tokens_count)
{
debug_display_mouse();
}