/
mouse.c
164 lines (131 loc) · 3.9 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
#include <kernel/mouse.h>
#include <kernel/com.h>
#include <kernel/irq.h>
#include <kernel/sys.h>
#include <stdio.h>
uint32_t current_byte = 0;
uint32_t bytes_per_packet = 3;
uint8_t packet[4] = { 0 };
uint32_t device;
int32_t x, y;
bool left_pressed;
bool right_pressed;
bool middle_pressed;
/* Initializes a mouse plugged in controller `dev`.
* Tries to enable as many of its features as possible.
*/
void init_mouse(uint32_t dev) {
device = dev;
x = 0;
y = 0;
left_pressed = false;
right_pressed = false;
irq_register_handler(IRQ12, mouse_handle_interrupt);
// Enable features
mouse_enable_scroll_wheel();
mouse_enable_five_buttons();
// Set mouse parameters
mouse_set_sample_rate(80);
mouse_set_resolution(0x00); // One unit per mm
mouse_set_scaling(false); // Disable acceleration
// Start receiving IRQ12s
ps2_write_device(device, PS2_DEV_ENABLE_SCAN);
ps2_expect_ack();
}
/* Receives one byte from the mouse and packages it in `packet`. Once that
* packet is full, calls `mouse_handle_packet`.
*/
void mouse_handle_interrupt(registers_t* regs) {
UNUSED(regs);
uint8_t byte = ps2_read(PS2_DATA);
// Try to stay synchronized by discarding obviously out of place bytes
if (current_byte == 0 && !(byte & MOUSE_ALWAYS_SET)) {
return;
}
packet[current_byte] = byte;
current_byte = (current_byte + 1) % bytes_per_packet;
// We've received a full packet
if (current_byte == 0) {
mouse_handle_packet();
}
}
void mouse_handle_packet() {
uint8_t flags = packet[0];
int32_t delta_x = (int32_t) packet[1];
int32_t delta_y = (int32_t) packet[2];
uint8_t extra = 0;
// Superior mice send four bytes
if (bytes_per_packet == 4) {
extra = packet[3];
if (extra & MOUSE_UNUSED_A || extra & MOUSE_UNUSED_B) {
return; // Unused bits are set: beware
}
}
// Packets with X or Y overflow are probably garbage
if (flags & MOUSE_X_OVERFLOW || flags & MOUSE_Y_OVERFLOW) {
return;
}
// Two's complement by hand
if (flags & MOUSE_X_NEG) {
delta_x |= 0xFFFFFF00;
}
if (flags & MOUSE_Y_NEG) {
delta_y |= 0xFFFFFF00;
}
left_pressed = flags & MOUSE_LEFT;
right_pressed = flags & MOUSE_RIGHT;
middle_pressed = flags & MOUSE_MIDDLE;
x += delta_x;
y -= delta_y; // Point the y-axis downward
printf("\x1B[s\x1B[23;65H");
printf("\x1B[K");
printf("%d;%d", x, y);
printf("\x1B[u");
}
void mouse_set_sample_rate(uint8_t rate) {
ps2_write_device(device, MOUSE_SET_SAMPLE);
ps2_expect_ack();
ps2_write_device(device, rate);
ps2_expect_ack();
}
void mouse_set_resolution(uint8_t level) {
ps2_write_device(device, MOUSE_SET_RESOLUTION);
ps2_expect_ack();
ps2_write_device(device, level);
ps2_expect_ack();
}
void mouse_set_scaling(bool enabled) {
uint8_t cmd = enabled ? MOUSE_ENABLE_SCALING : MOUSE_DISABLE_SCALING;
ps2_write_device(device, cmd);
ps2_expect_ack();
}
/* Uses a magic sequence to enable scroll wheel support.
*/
void mouse_enable_scroll_wheel() {
mouse_set_sample_rate(200);
mouse_set_sample_rate(100);
mouse_set_sample_rate(80);
uint32_t type = ps2_identify_device(device);
if (type == PS2_MOUSE_SCROLL_WHEEL) {
bytes_per_packet = 4;
printf("[MOUSE] Enabled scroll wheel\n");
} else {
printf("[MOUSE] Unable to enable scroll wheel\n");
}
}
/* Uses a magic sequence to enable five buttons support.
*/
void mouse_enable_five_buttons() {
if (bytes_per_packet != 4) {
return;
}
mouse_set_sample_rate(200);
mouse_set_sample_rate(200);
mouse_set_sample_rate(80);
uint32_t type = ps2_identify_device(device);
if (type != PS2_MOUSE_FIVE_BUTTONS) {
printf("[MOUSE] Mouse has fewer than five buttons\n");
} else {
printf("[MOUSE] Five buttons enabled\n");
}
}