use x86_64::instructions::port::Port;
use crate::{
error::ControllerError,
flags::{
ControllerConfigFlags, ControllerStatusFlags, InputPortFlags, OutputPortFlags,
TestPortFlags,
},
keyboard::Keyboard,
mouse::Mouse,
};
const DATA_REGISTER: u16 = 0x60;
const COMMAND_REGISTER: u16 = 0x64;
const DEFAULT_TIMEOUT: usize = 10_000;
type Result<T> = core::result::Result<T, ControllerError>;
#[repr(u8)]
pub(crate) enum Command {
ReadInternalRam = 0x20,
WriteInternalRam = 0x60,
DisableMouse = 0xa7,
EnableMouse = 0xa8,
TestMouse = 0xa9,
TestController = 0xaa,
TestKeyboard = 0xab,
DiagnosticDump = 0xac,
DisableKeyboard = 0xad,
EnableKeyboard = 0xae,
ReadControllerInput = 0xc0,
WriteLowInputNibbleToStatus = 0xc1,
WriteHighInputNibbleToStatus = 0xc2,
ReadControllerOutput = 0xd0,
WriteControllerOutput = 0xd1,
WriteKeyboardBuffer = 0xd2,
WriteMouseBuffer = 0xd3,
WriteMouse = 0xd4,
ReadTestPort = 0xe0,
PulseOutput = 0xf0,
}
#[derive(Debug)]
pub struct Controller {
command_register: Port<u8>,
data_register: Port<u8>,
timeout: usize,
}
impl Controller {
pub const unsafe fn new() -> Self {
Self::with_timeout(DEFAULT_TIMEOUT)
}
pub const unsafe fn with_timeout(timeout: usize) -> Self {
Self {
command_register: Port::new(COMMAND_REGISTER),
data_register: Port::new(DATA_REGISTER),
timeout,
}
}
pub const fn keyboard(&mut self) -> Keyboard<'_> {
Keyboard::new(self)
}
pub const fn mouse(&mut self) -> Mouse<'_> {
Mouse::new(self)
}
pub fn read_status(&mut self) -> ControllerStatusFlags {
ControllerStatusFlags::from_bits_truncate(unsafe { self.command_register.read() })
}
fn wait_for_read(&mut self) -> Result<()> {
let mut cycles = 0;
while cycles < self.timeout {
if self
.read_status()
.contains(ControllerStatusFlags::OUTPUT_FULL)
{
return Ok(());
}
cycles += 1;
}
Err(ControllerError::Timeout)
}
fn wait_for_write(&mut self) -> Result<()> {
let mut cycles = 0;
while cycles < self.timeout {
if !self
.read_status()
.contains(ControllerStatusFlags::INPUT_FULL)
{
return Ok(());
}
cycles += 1;
}
Err(ControllerError::Timeout)
}
pub(crate) fn write_command(&mut self, command: Command) -> Result<()> {
self.wait_for_write()?;
unsafe { self.command_register.write(command as u8) };
Ok(())
}
pub fn read_data(&mut self) -> Result<u8> {
self.wait_for_read()?;
Ok(unsafe { self.data_register.read() })
}
pub fn write_data(&mut self, data: u8) -> Result<()> {
self.wait_for_write()?;
unsafe { self.data_register.write(data) };
Ok(())
}
pub fn read_internal_ram(&mut self, byte_number: u8) -> Result<u8> {
let command = Command::ReadInternalRam as u8 | byte_number & 0x1f;
self.wait_for_write()?;
unsafe {
self.command_register.write(command as u8);
}
self.read_data()
}
pub fn write_internal_ram(&mut self, byte_number: u8, data: u8) -> Result<()> {
let command = Command::WriteInternalRam as u8 | byte_number & 0x1f;
self.wait_for_write()?;
unsafe {
self.command_register.write(command as u8);
}
self.write_data(data)
}
pub fn read_config(&mut self) -> Result<ControllerConfigFlags> {
Ok(ControllerConfigFlags::from_bits_truncate(
self.read_internal_ram(0)?,
))
}
pub fn write_config(&mut self, config: ControllerConfigFlags) -> Result<()> {
self.write_internal_ram(0, config.bits())
}
pub fn disable_mouse(&mut self) -> Result<()> {
self.write_command(Command::DisableMouse)
}
pub fn enable_mouse(&mut self) -> Result<()> {
self.write_command(Command::EnableMouse)
}
pub fn test_mouse(&mut self) -> Result<()> {
self.write_command(Command::TestMouse)?;
match self.read_data()? {
0x00 => Ok(()),
err => Err(ControllerError::TestFailed { response: err }),
}
}
pub fn test_controller(&mut self) -> Result<()> {
self.write_command(Command::TestController)?;
match self.read_data()? {
0x55 => Ok(()),
err => Err(ControllerError::TestFailed { response: err }),
}
}
pub fn test_keyboard(&mut self) -> Result<()> {
self.write_command(Command::TestKeyboard)?;
match self.read_data()? {
0x00 => Ok(()),
err => Err(ControllerError::TestFailed { response: err }),
}
}
pub fn diagnostic_dump(&mut self) -> Result<[u8; 32]> {
self.write_command(Command::DiagnosticDump)?;
let mut result = [0; 32];
for byte in result.iter_mut() {
*byte = self.read_data()?;
}
Ok(result)
}
pub fn disable_keyboard(&mut self) -> Result<()> {
self.write_command(Command::DisableKeyboard)
}
pub fn enable_keyboard(&mut self) -> Result<()> {
self.write_command(Command::EnableKeyboard)
}
pub fn read_input_port(&mut self) -> Result<InputPortFlags> {
self.write_command(Command::ReadControllerInput)?;
Ok(InputPortFlags::from_bits_truncate(self.read_data()?))
}
pub fn write_input_low_nibble_to_status(&mut self) -> Result<()> {
self.write_command(Command::WriteLowInputNibbleToStatus)
}
pub fn write_input_high_nibble_to_status(&mut self) -> Result<()> {
self.write_command(Command::WriteHighInputNibbleToStatus)
}
pub fn read_output_port(&mut self) -> Result<OutputPortFlags> {
self.write_command(Command::ReadControllerOutput)?;
Ok(OutputPortFlags::from_bits_truncate(self.read_data()?))
}
pub fn write_output_port(&mut self, output: OutputPortFlags) -> Result<()> {
self.write_command(Command::WriteControllerOutput)?;
self.write_data(output.bits())
}
pub fn write_keyboard_buffer(&mut self, data: u8) -> Result<()> {
self.write_command(Command::WriteKeyboardBuffer)?;
self.write_data(data)
}
pub fn write_mouse_buffer(&mut self, data: u8) -> Result<()> {
self.write_command(Command::WriteMouseBuffer)?;
self.write_data(data)
}
pub fn write_mouse(&mut self, data: u8) -> Result<()> {
self.write_command(Command::WriteMouse)?;
self.write_data(data)
}
pub fn read_test_port(&mut self) -> Result<TestPortFlags> {
self.write_command(Command::ReadTestPort)?;
Ok(TestPortFlags::from_bits_truncate(self.read_data()?))
}
pub fn pulse_output_low_nibble(&mut self, data: u8) -> Result<()> {
let command = Command::PulseOutput as u8 | data;
self.wait_for_write()?;
unsafe {
self.command_register.write(command as u8);
}
Ok(())
}
}