good_os_framework/drivers/
mouse.rs1use bitflags::bitflags;
2use spin::{Lazy, Mutex};
3use x86_64::instructions::port::Port;
4
5const PORT_READ_TRY_TIMES: u16 = 10_000;
6
7pub static MOUSE: Lazy<Mutex<Mouse>> = Lazy::new(|| Mutex::new(Mouse::new()));
8
9pub fn init() {
10 let mut mouse = MOUSE.lock();
11 match mouse.init() {
12 Ok(_) => {
13 mouse.set_complete_handler(mouse_complete_handler);
14 log::debug!("Mouse Type: {:?}", mouse.mouse_type);
15 log::info!("Mouse initialized successfully!");
16 }
17 Err(err) => log::error!("Failed to initialize mouse: {}", err),
18 }
19}
20
21fn mouse_complete_handler(_mouse_state: MouseState) {
22 }
24
25bitflags! {
26 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27 struct MouseFlags: u8 {
28 const LEFT_BUTTON = 0b0000_0001;
29 const RIGHT_BUTTON = 0b0000_0010;
30 const MIDDLE_BUTTON = 0b0000_0100;
31 const ALWAYS_ONE = 0b0000_1000;
32 const X_SIGN = 0b0001_0000;
33 const Y_SIGN = 0b0010_0000;
34 const X_OVERFLOW = 0b0100_0000;
35 const Y_OVERFLOW = 0b1000_0000;
36 }
37}
38
39#[derive(Debug, Copy, Clone)]
40enum MouseAdditionalFlags {
41 FirstButton = 0b0100_0001,
42 SecondButton = 0b0111_1111,
43 ScrollUp = 0b0000_0001,
44 ScrollDown = 0b0000_1111,
45 None,
46}
47
48#[derive(Debug)]
49enum MouseType {
50 Standard,
51 OnlyScroll,
52 FiveButton,
53}
54
55#[derive(Debug)]
56pub struct Mouse {
57 command_port: Port<u8>,
58 data_port: Port<u8>,
59 current_packet_index: u16,
60 current_state: MouseState,
61 mouse_type: MouseType,
62 complete_handler: Option<fn(MouseState)>,
63}
64
65#[derive(Debug, Copy, Clone)]
66pub struct MouseState {
67 flags: MouseFlags,
68 additional_flags: MouseAdditionalFlags,
69 move_x: i16,
70 move_y: i16,
71}
72
73impl MouseState {
74 pub const fn new() -> MouseState {
75 MouseState {
76 flags: MouseFlags::empty(),
77 additional_flags: MouseAdditionalFlags::None,
78 move_x: 0,
79 move_y: 0,
80 }
81 }
82}
83
84impl Mouse {
85 pub const fn new() -> Mouse {
86 Mouse {
87 command_port: Port::new(0x64),
88 data_port: Port::new(0x60),
89 current_packet_index: 0,
90 current_state: MouseState::new(),
91 mouse_type: MouseType::Standard,
92 complete_handler: None,
93 }
94 }
95
96 pub fn init(&mut self) -> Result<(), &'static str> {
97 unsafe {
98 self.enable_packet_streaming()?
99 .enable_scroll_wheel()?
100 .enable_additional_button()?;
101 }
102 Ok(())
103 }
104
105 pub fn process_packet(&mut self, packet: u8) {
106 let modulo = match self.mouse_type {
107 MouseType::Standard => 3,
108 _ => 4,
109 };
110 match self.current_packet_index % modulo {
111 0 => {
112 let flags = MouseFlags::from_bits_truncate(packet);
113 if !flags.contains(MouseFlags::ALWAYS_ONE) {
114 return;
115 }
116 self.current_state.flags = flags;
117 }
118 1 => {
119 if !self.current_state.flags.contains(MouseFlags::X_OVERFLOW) {
120 self.current_state.move_x = packet as i16;
121 if self.current_state.flags.contains(MouseFlags::X_SIGN) {
122 self.current_state.move_x = ((packet as u16) | 0xFF00) as i16;
123 }
124 }
125 }
126 2 => {
127 if !self.current_state.flags.contains(MouseFlags::Y_OVERFLOW) {
128 self.current_state.move_y = packet as i16;
129 if self.current_state.flags.contains(MouseFlags::Y_SIGN) {
130 self.current_state.move_y = ((packet as u16) | 0xFF00) as i16;
131 }
132 }
133 }
134 3 => {
135 self.current_state.additional_flags = match packet {
136 0b0100_0001 => MouseAdditionalFlags::FirstButton,
137 0b0111_1111 => MouseAdditionalFlags::SecondButton,
138 0b0000_0001 => MouseAdditionalFlags::ScrollUp,
139 0b1111_1111 => MouseAdditionalFlags::ScrollDown,
141 0b0000_1111 => MouseAdditionalFlags::ScrollDown,
142 _ => MouseAdditionalFlags::None,
143 };
144 }
145 _ => unreachable!(),
146 }
147 if self.current_packet_index % modulo == modulo - 1 {
148 if self.complete_handler.is_some() {
149 (self.complete_handler.unwrap())(self.current_state);
150 }
151 }
152 self.current_packet_index += 1;
153 self.current_packet_index %= modulo;
154 }
155
156 pub fn set_complete_handler(&mut self, handler: fn(MouseState)) {
157 self.complete_handler = Some(handler);
158 }
159
160 unsafe fn enable_packet_streaming(&mut self) -> Result<&mut Self, &'static str> {
161 Ok(self.send_command(0xf4 as u8)?)
162 }
163
164 unsafe fn enable_scroll_wheel(&mut self) -> Result<&mut Self, &'static str> {
165 self.send_command(0xf3)?.send_command(200)?;
166 self.send_command(0xf3)?.send_command(100)?;
167 self.send_command(0xf3)?.send_command(80)?;
168 self.send_command(0xf2 as u8)?;
169 if self.read_data_port()? == 0x3 {
170 self.mouse_type = MouseType::OnlyScroll;
171 }
172 Ok(self)
173 }
174
175 unsafe fn enable_additional_button(&mut self) -> Result<&mut Self, &'static str> {
176 self.send_command(0xf3)?.send_command(200)?;
177 self.send_command(0xf3)?.send_command(200)?;
178 self.send_command(0xf3)?.send_command(80)?;
179 self.send_command(0xf2 as u8)?;
180 if self.read_data_port()? == 0x4 {
181 self.mouse_type = MouseType::FiveButton;
182 }
183 Ok(self)
184 }
185
186 unsafe fn send_command(&mut self, command: u8) -> Result<&mut Self, &'static str> {
187 self.write_command_port(0xd4)?;
188 self.write_data_port(command)?;
189 for _ in 0..PORT_READ_TRY_TIMES {
190 if self.read_data_port()? == 0xfa {
191 return Ok(self);
192 }
193 }
194 Err("Did not receive ack response from mouse!")
195 }
196
197 unsafe fn read_data_port(&mut self) -> Result<u8, &'static str> {
198 self.wait_for_read()?;
199 Ok(self.data_port.read())
200 }
201
202 unsafe fn write_command_port(&mut self, value: u8) -> Result<(), &'static str> {
203 self.wait_for_write()?;
204 Ok(self.command_port.write(value))
205 }
206
207 unsafe fn write_data_port(&mut self, value: u8) -> Result<(), &'static str> {
208 self.wait_for_write()?;
209 Ok(self.data_port.write(value))
210 }
211
212 unsafe fn wait_for_read(&mut self) -> Result<(), &'static str> {
213 for _ in 0..PORT_READ_TRY_TIMES {
214 if self.command_port.read() & 0x1 == 1 {
215 return Ok(());
216 }
217 }
218 Err("Tried too many times to wait command port to be ready to read!")
219 }
220
221 unsafe fn wait_for_write(&mut self) -> Result<(), &'static str> {
222 for _ in 0..PORT_READ_TRY_TIMES {
223 if self.command_port.read() & 0x2 == 0 {
224 return Ok(());
225 }
226 }
227 Err("Tried too many times to wait command port to be ready to write!")
228 }
229}