Skip to content

Instantly share code, notes, and snippets.

@Restioson Restioson/hackish_solution.rs Secret
Created Dec 31, 2017

Embed
What would you like to do?
/// A PS2 device
pub trait Device: DeviceHelper {
fn port(&self) -> DevicePort;
/// Enables this device
///
/// # Examples
///
/// ```rust,no_run
/// let controller = ps2::CONTROLLER.lock();
/// let device = controller.device(DevicePort::Keyboard);
/// match device.enable() {
/// Ok(()) => println!("Device enabled"),
/// Err(err) => println!("Error enabling device: {:?}", err)
/// }
///
/// ```
fn enable(&self) -> Result<(), Ps2Error> {
let cmd = if self.port() == DevicePort::One {
ControllerCommand::EnablePort1
} else {
ControllerCommand::EnablePort2
};
io::write(&STATUS_COMMAND_PORT, cmd as u8)
}
/// Disables this device
///
/// # Examples
///
/// ```rust,no_run
/// let controller = ps2::CONTROLLER.lock();
/// let device = controller.device(DevicePort::Keyboard);
/// match device.disable() {
/// Ok(()) => println!("Device disabled"),
/// Err(err) => println!("Error disabling device: {:?}", err)
/// }
/// ```
// TODO must be public?
fn disable(&self) -> Result<(), Ps2Error> {
let cmd = if self.port() == DevicePort::One {
ControllerCommand::DisablePort1
} else {
ControllerCommand::DisablePort2
};
io::write(&STATUS_COMMAND_PORT, cmd as u8)
}
/// Enables scanning for this device. This will signal the device to begin sending data again,
/// like scancodes from keyboards and updates from mice.
fn enable_scanning(&self) -> Result<(), Ps2Error> { // TODO mut or not
self.command(DeviceCommand::EnableScanning as u8)
}
/// Disables scanning for this device. This will stop the device from sending data, like
/// scancodes from keyboards and updates from mice.
fn disable_scanning(&self) -> Result<(), Ps2Error> {
self.command(DeviceCommand::DisableScanning as u8)
}
/// Sets the parameters of this device to default parameters
fn set_defaults(&self) -> Result<(), Ps2Error> {
self.command(DeviceCommand::SetDefaults as u8)
}
/// Resets this device
///
/// # Examples
///
/// ```rust,no_run
/// let controller = ps2::CONTROLLER.lock();
/// let device = controller.device(DevicePort::Keyboard);
/// match device.reset() {
/// Ok(()) => println!("Device reset"),
/// Err(err) => println!("Error resetting device: {:?}", err)
/// }
/// ```
fn reset(&self) -> Result<(), Ps2Error> {
self.command(DeviceCommand::Reset as u8)
}
fn identify(&self) -> Result<DeviceType, Ps2Error> {
// TODO
unimplemented!()
}
// TODO caching with interrupts?
fn state(&self) -> Result<DeviceState, Ps2Error> {
// TODO
unimplemented!()
}
}
/// Helper trait for devices which allows sending commands to be private
trait DeviceHelper {
fn state_helper(&self) -> Result<DeviceState, Ps2Error>;
fn port_helper(&self) -> DevicePort;
/// Sends a raw command code to this device
// TODO no?
// TODO needs mut?
// TODO r these pub
fn command(&self, cmd: u8) -> Result<(), Ps2Error> {
if self.state_helper()? != DeviceState::Enabled {
return Err(Ps2Error::DeviceDisabled)
}
// If second PS2 port, send context switch command
if self.port_helper() == DevicePort::Two {
io::write(&STATUS_COMMAND_PORT, ControllerCommand::WriteInputPort2 as u8)?;
}
for _ in 0..4 {
io::write(&io::DEVICE_DATA_PORT, cmd)?;
match io::read(&DEVICE_DATA_PORT) {
Ok(RESEND) => continue,
Ok(ACK) => return Ok(()), // TODO check dis
Ok(unknown) => return Err(Ps2Error::UnexpectedResponse(unknown)),
Err(err) => return Err(err),
}
}
Err(Ps2Error::NoData)
}
/// Sends a raw command code to this device and returns
// TODO no?
// TODO needs mut?
fn command_ret(&self, cmd: u8) -> Result<u8, Ps2Error> {
if self.state_helper()? != DeviceState::Enabled {
return Err(Ps2Error::DeviceDisabled)
}
if self.port_helper() == DevicePort::Two {
io::write(&STATUS_COMMAND_PORT, ControllerCommand::WriteInputPort2 as u8)?;
}
for _ in 0..4 {
io::write(&io::DEVICE_DATA_PORT, cmd)?;
match io::read(&DEVICE_DATA_PORT) {
Ok(RESEND) => continue,
result => return result,
}
}
Err(Ps2Error::NoData)
}
/// Sends a raw command to this PS2 device with data
// TODO needs mut?
fn command_data(&self, cmd: u8, data: u8) -> Result<(), Ps2Error> {
if self.state_helper()? != DeviceState::Enabled {
return Err(Ps2Error::DeviceDisabled)
}
// If second PS2 port, send context switch command
if self.port_helper() == DevicePort::Two {
io::write(&STATUS_COMMAND_PORT, ControllerCommand::WriteInputPort2 as u8)?;
}
for _ in 0..4 {
io::write(&io::DEVICE_DATA_PORT, cmd)?;
match io::read(&DEVICE_DATA_PORT) {
Ok(RESEND) => continue,
Ok(ACK) => break, // TODO check dis
Ok(unknown) => return Err(Ps2Error::UnexpectedResponse(unknown)),
Err(err) => return Err(err),
}
}
for _ in 0..4 {
io::write(&io::DEVICE_DATA_PORT, data)?;
match io::read(&DEVICE_DATA_PORT) {
Ok(RESEND) => continue,
Ok(ACK) => return Ok(()), // TODO check dis
Ok(unknown) => return Err(Ps2Error::UnexpectedResponse(unknown)),
Err(err) => return Err(err),
}
}
Err(Ps2Error::NoData)
}
}
impl<T: Device> DeviceHelper for T {
fn state_helper(&self) -> Result<DeviceState, Ps2Error> {
self.state()
}
fn port_helper(&self) -> DevicePort {
self.port()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.