ps2/
controller.rs

1use x86_64::instructions::port::Port;
2
3use crate::{
4    error::ControllerError,
5    flags::{
6        ControllerConfigFlags, ControllerStatusFlags, InputPortFlags, OutputPortFlags,
7        TestPortFlags,
8    },
9    keyboard::Keyboard,
10    mouse::Mouse,
11};
12
13const DATA_REGISTER: u16 = 0x60;
14const COMMAND_REGISTER: u16 = 0x64;
15const DEFAULT_TIMEOUT: usize = 10_000;
16
17type Result<T> = core::result::Result<T, ControllerError>;
18
19#[repr(u8)]
20pub(crate) enum Command {
21    ReadInternalRam = 0x20,
22    WriteInternalRam = 0x60,
23    DisableMouse = 0xa7,
24    EnableMouse = 0xa8,
25    TestMouse = 0xa9,
26    TestController = 0xaa,
27    TestKeyboard = 0xab,
28    DiagnosticDump = 0xac,
29    DisableKeyboard = 0xad,
30    EnableKeyboard = 0xae,
31    ReadControllerInput = 0xc0,
32    WriteLowInputNibbleToStatus = 0xc1,
33    WriteHighInputNibbleToStatus = 0xc2,
34    ReadControllerOutput = 0xd0,
35    WriteControllerOutput = 0xd1,
36    WriteKeyboardBuffer = 0xd2,
37    WriteMouseBuffer = 0xd3,
38    WriteMouse = 0xd4,
39    ReadTestPort = 0xe0,
40    PulseOutput = 0xf0,
41}
42
43/// The PS/2 controller.
44///
45/// Provides the functionality of an Intel 8042 chip. Many computers nowadays don't have PS/2
46/// connectors, but emulate the mouse and keyboard as PS/2 devices through USB. The implementation
47/// of this emulation is usually different from manufacturer to manufacturer and cannot always be
48/// relied upon to perform correctly. Therefore, if you're writing an operating system, you should
49/// disable this legacy support once the USB controller has been initialized.
50#[derive(Debug)]
51pub struct Controller {
52    command_register: Port<u8>,
53    data_register: Port<u8>,
54    timeout: usize,
55}
56
57impl Controller {
58    /// Create a handle to the PS/2 controller. Uses a default IO timeout of 10,000 tries.
59    ///
60    /// # Safety
61    ///
62    /// Ensure that IO ports `0x60` and `0x64` are not accessed by any other code, and that only
63    /// one `Controller` accesses those ports at any point in time.
64    pub const unsafe fn new() -> Self {
65        Self::with_timeout(DEFAULT_TIMEOUT)
66    }
67
68    /// Like `new`, but allows specifying an IO timeout, which is the number of times an IO
69    /// operation will be attempted before returning [`ControllerError::Timeout`].
70    pub const unsafe fn with_timeout(timeout: usize) -> Self {
71        Self {
72            command_register: Port::new(COMMAND_REGISTER),
73            data_register: Port::new(DATA_REGISTER),
74            timeout,
75        }
76    }
77
78    /// Obtain a handle to the keyboard.
79    pub const fn keyboard(&mut self) -> Keyboard<'_> {
80        Keyboard::new(self)
81    }
82
83    /// Obtain a handle to the mouse.
84    pub const fn mouse(&mut self) -> Mouse<'_> {
85        Mouse::new(self)
86    }
87
88    /// Read the status register of the controller.
89    pub fn read_status(&mut self) -> ControllerStatusFlags {
90        ControllerStatusFlags::from_bits_truncate(unsafe { self.command_register.read() })
91    }
92
93    fn wait_for_read(&mut self) -> Result<()> {
94        let mut cycles = 0;
95        while cycles < self.timeout {
96            if self
97                .read_status()
98                .contains(ControllerStatusFlags::OUTPUT_FULL)
99            {
100                return Ok(());
101            }
102            cycles += 1;
103        }
104        Err(ControllerError::Timeout)
105    }
106
107    fn wait_for_write(&mut self) -> Result<()> {
108        let mut cycles = 0;
109        while cycles < self.timeout {
110            if !self
111                .read_status()
112                .contains(ControllerStatusFlags::INPUT_FULL)
113            {
114                return Ok(());
115            }
116            cycles += 1;
117        }
118        Err(ControllerError::Timeout)
119    }
120
121    pub(crate) fn write_command(&mut self, command: Command) -> Result<()> {
122        self.wait_for_write()?;
123        unsafe { self.command_register.write(command as u8) };
124        Ok(())
125    }
126
127    /// Read a byte from the data buffer once it is full.
128    ///
129    /// If there is no data available to read within the configured timeout, this will return
130    /// [`ControllerError::Timeout`].
131    pub fn read_data(&mut self) -> Result<u8> {
132        self.wait_for_read()?;
133        Ok(unsafe { self.data_register.read() })
134    }
135
136    /// Write a byte to the data buffer once it is empty.
137    ///
138    /// If a write cannot be performed within the configured timeout, this will return
139    /// [`ControllerError::Timeout`].
140    pub fn write_data(&mut self, data: u8) -> Result<()> {
141        self.wait_for_write()?;
142        unsafe { self.data_register.write(data) };
143        Ok(())
144    }
145
146    /// Read a byte from the controller's internal RAM.
147    ///
148    /// The desired byte index must be between 0 and 31. Byte 0 is also known as the configuration
149    /// byte or command byte.
150    pub fn read_internal_ram(&mut self, byte_number: u8) -> Result<u8> {
151        // Limit from 0 - 31, start command byte at 0x20
152        let command = Command::ReadInternalRam as u8 | byte_number & 0x1f;
153        // Since we did some bit fiddling, we can't use write_command
154        self.wait_for_write()?;
155        unsafe {
156            self.command_register.write(command as u8);
157        }
158        self.read_data()
159    }
160
161    /// Write a byte to the controller's internal RAM.
162    ///
163    /// The desired byte index must be between 0 and 31. Byte 0 is also known as the configuration
164    /// byte or command byte.
165    pub fn write_internal_ram(&mut self, byte_number: u8, data: u8) -> Result<()> {
166        // Limit from 0 - 31, start command byte at 0x60
167        let command = Command::WriteInternalRam as u8 | byte_number & 0x1f;
168        // Since we did some bit fiddling, we can't use write_command
169        self.wait_for_write()?;
170        unsafe {
171            self.command_register.write(command as u8);
172        }
173        self.write_data(data)
174    }
175
176    /// Read the configuration byte (or command byte) of the controller. This is the same as
177    /// reading byte 0 of the internal RAM.
178    pub fn read_config(&mut self) -> Result<ControllerConfigFlags> {
179        Ok(ControllerConfigFlags::from_bits_truncate(
180            self.read_internal_ram(0)?,
181        ))
182    }
183
184    /// Write the configuration byte (or command byte) of the controller. This is the same as
185    /// writing to byte 0 of the internal RAM.
186    pub fn write_config(&mut self, config: ControllerConfigFlags) -> Result<()> {
187        self.write_internal_ram(0, config.bits())
188    }
189
190    /// Disable the mouse. Sets the [`ControllerConfigFlags::DISABLE_MOUSE`] flag.
191    pub fn disable_mouse(&mut self) -> Result<()> {
192        self.write_command(Command::DisableMouse)
193    }
194
195    /// Enable the mouse. Clears the [`ControllerConfigFlags::DISABLE_MOUSE`] flag.
196    pub fn enable_mouse(&mut self) -> Result<()> {
197        self.write_command(Command::EnableMouse)
198    }
199
200    /// Perform a self-test on the mouse.
201    ///
202    /// Returns [`ControllerError::TestFailed`] if the test fails.
203    pub fn test_mouse(&mut self) -> Result<()> {
204        self.write_command(Command::TestMouse)?;
205        match self.read_data()? {
206            0x00 => Ok(()),
207            err => Err(ControllerError::TestFailed { response: err }),
208        }
209    }
210
211    /// Perform a self-test on the controller.
212    ///
213    /// Returns [`ControllerError::TestFailed`] if the test fails.
214    pub fn test_controller(&mut self) -> Result<()> {
215        self.write_command(Command::TestController)?;
216        match self.read_data()? {
217            0x55 => Ok(()),
218            err => Err(ControllerError::TestFailed { response: err }),
219        }
220    }
221
222    /// Perform a self-test on the keyboard.
223    ///
224    /// Returns [`ControllerError::TestFailed`] if the test fails.
225    pub fn test_keyboard(&mut self) -> Result<()> {
226        self.write_command(Command::TestKeyboard)?;
227        match self.read_data()? {
228            0x00 => Ok(()),
229            err => Err(ControllerError::TestFailed { response: err }),
230        }
231    }
232
233    /// Dump all bytes of the controller's internal RAM.
234    // TODO: Test this, eventually. I wasn't able to get it working with any of my devices
235    pub fn diagnostic_dump(&mut self) -> Result<[u8; 32]> {
236        self.write_command(Command::DiagnosticDump)?;
237        let mut result = [0; 32];
238        for byte in result.iter_mut() {
239            *byte = self.read_data()?;
240        }
241        Ok(result)
242    }
243
244    /// Disable the keyboard.
245    ///
246    /// Sets the [`ControllerConfigFlags::DISABLE_KEYBOARD`] flag.
247    pub fn disable_keyboard(&mut self) -> Result<()> {
248        self.write_command(Command::DisableKeyboard)
249    }
250
251    /// Enable the keyboard.
252    ///
253    /// Clears the [`ControllerConfigFlags::DISABLE_KEYBOARD`] flag.
254    pub fn enable_keyboard(&mut self) -> Result<()> {
255        self.write_command(Command::EnableKeyboard)
256    }
257
258    /// Read the state of the controller's input port.
259    pub fn read_input_port(&mut self) -> Result<InputPortFlags> {
260        self.write_command(Command::ReadControllerInput)?;
261        Ok(InputPortFlags::from_bits_truncate(self.read_data()?))
262    }
263
264    /// Write the low nibble of the controller's input port to the low nibble of the controller
265    /// status register.
266    pub fn write_input_low_nibble_to_status(&mut self) -> Result<()> {
267        self.write_command(Command::WriteLowInputNibbleToStatus)
268    }
269
270    /// Write the high nibble of the controller's input port to the high nibble of the controller
271    /// status register.
272    pub fn write_input_high_nibble_to_status(&mut self) -> Result<()> {
273        self.write_command(Command::WriteHighInputNibbleToStatus)
274    }
275
276    /// Read the state of the controller's output port.
277    pub fn read_output_port(&mut self) -> Result<OutputPortFlags> {
278        self.write_command(Command::ReadControllerOutput)?;
279        Ok(OutputPortFlags::from_bits_truncate(self.read_data()?))
280    }
281
282    /// Write the state of the controller's output port.
283    pub fn write_output_port(&mut self, output: OutputPortFlags) -> Result<()> {
284        self.write_command(Command::WriteControllerOutput)?;
285        self.write_data(output.bits())
286    }
287
288    /// Write a byte to the data buffer as if it were received from the keyboard.
289    ///
290    /// This will trigger an interrupt if interrupts are enabled.
291    pub fn write_keyboard_buffer(&mut self, data: u8) -> Result<()> {
292        self.write_command(Command::WriteKeyboardBuffer)?;
293        self.write_data(data)
294    }
295
296    /// Write a byte to the data buffer as if it were received from the mouse.
297    ///
298    /// This will trigger an interrupt if interrupts are enabled.
299    pub fn write_mouse_buffer(&mut self, data: u8) -> Result<()> {
300        self.write_command(Command::WriteMouseBuffer)?;
301        self.write_data(data)
302    }
303
304    /// Write a byte to the mouse's data buffer.
305    pub fn write_mouse(&mut self, data: u8) -> Result<()> {
306        self.write_command(Command::WriteMouse)?;
307        self.write_data(data)
308    }
309
310    /// Read the state of the controller's test port.
311    pub fn read_test_port(&mut self) -> Result<TestPortFlags> {
312        self.write_command(Command::ReadTestPort)?;
313        Ok(TestPortFlags::from_bits_truncate(self.read_data()?))
314    }
315
316    /// Pulse the low nibble of the given byte onto the lower nibble of the controller output port.
317    pub fn pulse_output_low_nibble(&mut self, data: u8) -> Result<()> {
318        // Make the high nibble all 1's
319        let command = Command::PulseOutput as u8 | data;
320        // Since we did some bit fiddling, we can't use write_command
321        self.wait_for_write()?;
322        unsafe {
323            self.command_register.write(command as u8);
324        }
325        Ok(())
326    }
327}