veridian_kernel/drivers/
mouse.rs1use core::sync::atomic::{AtomicBool, AtomicI32, AtomicU16, Ordering};
8
9pub const BUTTON_LEFT: u8 = 0x01;
11pub const BUTTON_RIGHT: u8 = 0x02;
12pub const BUTTON_MIDDLE: u8 = 0x04;
13
14#[derive(Debug, Clone, Copy)]
16pub struct MouseEvent {
17 pub dx: i16,
18 pub dy: i16,
19 pub buttons: u8,
20}
21
22static SCREEN_WIDTH: AtomicU16 = AtomicU16::new(1280);
24static SCREEN_HEIGHT: AtomicU16 = AtomicU16::new(800);
25
26static CURSOR_X: AtomicI32 = AtomicI32::new(640);
28static CURSOR_Y: AtomicI32 = AtomicI32::new(400);
29
30static INITIALIZED: AtomicBool = AtomicBool::new(false);
31
32pub fn cursor_position() -> (i32, i32) {
34 (
35 CURSOR_X.load(Ordering::Relaxed),
36 CURSOR_Y.load(Ordering::Relaxed),
37 )
38}
39
40pub fn set_screen_bounds(width: u16, height: u16) {
42 SCREEN_WIDTH.store(width, Ordering::Relaxed);
43 SCREEN_HEIGHT.store(height, Ordering::Relaxed);
44}
45
46pub fn is_initialized() -> bool {
48 INITIALIZED.load(Ordering::Acquire)
49}
50
51#[cfg(target_arch = "x86_64")]
56mod x86_64_impl {
57 use core::sync::atomic::AtomicUsize;
58
59 use spin::Mutex;
60
61 use super::*;
62
63 const EVENT_BUFFER_SIZE: usize = 64;
65
66 struct MouseBuffer {
67 buf: [MouseEvent; EVENT_BUFFER_SIZE],
68 head: AtomicUsize,
69 tail: AtomicUsize,
70 }
71
72 impl MouseBuffer {
73 const fn new() -> Self {
74 Self {
75 buf: [MouseEvent {
76 dx: 0,
77 dy: 0,
78 buttons: 0,
79 }; EVENT_BUFFER_SIZE],
80 head: AtomicUsize::new(0),
81 tail: AtomicUsize::new(0),
82 }
83 }
84
85 fn push(&mut self, event: MouseEvent) {
86 let head = self.head.load(Ordering::Relaxed);
87 let next = (head + 1) & (EVENT_BUFFER_SIZE - 1);
88 let tail = self.tail.load(Ordering::Acquire);
89 if next == tail {
90 return; }
92 self.buf[head] = event;
93 self.head.store(next, Ordering::Release);
94 }
95
96 fn pop(&self) -> Option<MouseEvent> {
97 let tail = self.tail.load(Ordering::Relaxed);
98 let head = self.head.load(Ordering::Acquire);
99 if tail == head {
100 return None;
101 }
102 let event = self.buf[tail];
103 self.tail
104 .store((tail + 1) & (EVENT_BUFFER_SIZE - 1), Ordering::Release);
105 Some(event)
106 }
107
108 fn has_data(&self) -> bool {
109 self.tail.load(Ordering::Relaxed) != self.head.load(Ordering::Acquire)
110 }
111 }
112
113 unsafe impl Send for MouseBuffer {}
116 unsafe impl Sync for MouseBuffer {}
117
118 static MOUSE_BUFFER: Mutex<MouseBuffer> = Mutex::new(MouseBuffer::new());
119
120 struct PacketState {
122 buf: [u8; 3],
123 idx: usize,
124 }
125
126 static PACKET_STATE: Mutex<PacketState> = Mutex::new(PacketState {
127 buf: [0; 3],
128 idx: 0,
129 });
130
131 #[inline]
133 fn wait_input() {
134 for _ in 0..10_000 {
135 let status = unsafe { crate::arch::x86_64::inb(0x64) };
137 if (status & 0x02) == 0 {
138 return;
139 }
140 }
141 }
142
143 #[inline]
145 fn wait_output() -> bool {
146 for _ in 0..10_000 {
147 let status = unsafe { crate::arch::x86_64::inb(0x64) };
149 if (status & 0x01) != 0 {
150 return true;
151 }
152 }
153 false
154 }
155
156 fn mouse_write(cmd: u8) {
158 wait_input();
159 unsafe {
161 crate::arch::x86_64::outb(0x64, 0xD4); }
164 wait_input();
165 unsafe {
167 crate::arch::x86_64::outb(0x60, cmd);
168 }
169 }
170
171 fn mouse_read() -> Option<u8> {
173 if wait_output() {
174 Some(unsafe { crate::arch::x86_64::inb(0x60) })
176 } else {
177 None
178 }
179 }
180
181 pub fn init() {
183 wait_input();
185 unsafe {
187 crate::arch::x86_64::outb(0x64, 0xA8); }
189
190 wait_input();
192 unsafe {
194 crate::arch::x86_64::outb(0x64, 0x20);
195 }
196 let config_byte = if wait_output() {
197 Some(unsafe { crate::arch::x86_64::inb(0x60) })
199 } else {
200 None
201 };
202 if let Some(mut config) = config_byte {
203 config |= 0x02; config &= !0x20; wait_input();
208 unsafe {
210 crate::arch::x86_64::outb(0x64, 0x60); }
212 wait_input();
213 unsafe {
215 crate::arch::x86_64::outb(0x60, config);
216 }
217 }
218
219 mouse_write(0xFF);
221 let _ = mouse_read(); let _ = mouse_read(); let _ = mouse_read(); mouse_write(0xF6);
227 let _ = mouse_read(); mouse_write(0xF4);
231 let _ = mouse_read(); INITIALIZED.store(true, Ordering::Release);
234 crate::println!("[MOUSE] PS/2 mouse initialized");
235 }
236
237 pub fn poll_mouse_byte(byte: u8) {
244 if !INITIALIZED.load(Ordering::Acquire) {
245 return;
246 }
247
248 let mut pkt = PACKET_STATE.lock();
249 let idx = pkt.idx;
250 pkt.buf[idx] = byte;
251 pkt.idx = idx + 1;
252
253 if pkt.idx >= 3 {
254 pkt.idx = 0;
255 let status_byte = pkt.buf[0];
256
257 if (status_byte & 0x08) == 0 {
259 return; }
261
262 let buttons = status_byte & 0x07;
263
264 let mut dx = pkt.buf[1] as i16;
266 let mut dy = pkt.buf[2] as i16;
267 if (status_byte & 0x10) != 0 {
268 dx -= 256; }
270 if (status_byte & 0x20) != 0 {
271 dy -= 256; }
273
274 dy = -dy;
276
277 let sw = SCREEN_WIDTH.load(Ordering::Relaxed) as i32;
279 let sh = SCREEN_HEIGHT.load(Ordering::Relaxed) as i32;
280 let mut cx = CURSOR_X.load(Ordering::Relaxed) + dx as i32;
281 let mut cy = CURSOR_Y.load(Ordering::Relaxed) + dy as i32;
282 cx = cx.clamp(0, sw - 1);
283 cy = cy.clamp(0, sh - 1);
284 CURSOR_X.store(cx, Ordering::Relaxed);
285 CURSOR_Y.store(cy, Ordering::Relaxed);
286
287 let event = MouseEvent { dx, dy, buttons };
288 MOUSE_BUFFER.lock().push(event);
289 }
290 }
291
292 pub fn poll_mouse() {
300 if !INITIALIZED.load(Ordering::Acquire) {
301 return;
302 }
303
304 let status = unsafe { crate::arch::x86_64::inb(0x64) };
307 if (status & 0x21) != 0x21 {
308 return;
310 }
311
312 let byte = unsafe { crate::arch::x86_64::inb(0x60) };
314 poll_mouse_byte(byte);
315 }
316
317 pub fn read_event() -> Option<MouseEvent> {
319 MOUSE_BUFFER.lock().pop()
320 }
321
322 pub fn has_data() -> bool {
324 MOUSE_BUFFER.lock().has_data()
325 }
326}
327
328#[cfg(target_arch = "x86_64")]
329pub use x86_64_impl::{has_data, init, poll_mouse, poll_mouse_byte, read_event};
330
331#[cfg(not(target_arch = "x86_64"))]
336pub fn init() {}
337
338#[cfg(not(target_arch = "x86_64"))]
339pub fn poll_mouse() {}
340
341#[cfg(not(target_arch = "x86_64"))]
342pub fn poll_mouse_byte(_byte: u8) {}
343
344#[cfg(not(target_arch = "x86_64"))]
345pub fn read_event() -> Option<MouseEvent> {
346 None
347}
348
349#[cfg(not(target_arch = "x86_64"))]
350pub fn has_data() -> bool {
351 false
352}