p2sd: Add timeout handling
This commit is contained in:
+1
-1
@@ -6,4 +6,4 @@ edition = "2018"
|
||||
[dependencies]
|
||||
bitflags = "1"
|
||||
orbclient = "0.3.27"
|
||||
redox_syscall = "0.2.9"
|
||||
redox_syscall = "0.2.11"
|
||||
|
||||
+116
-76
@@ -1,5 +1,13 @@
|
||||
use syscall::io::{Io, Pio, ReadOnly, WriteOnly};
|
||||
|
||||
use std::{thread, time};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ReadTimeout,
|
||||
WriteTimeout,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct StatusFlags: u8 {
|
||||
const OUTPUT_FULL = 1;
|
||||
@@ -94,12 +102,30 @@ impl Ps2 {
|
||||
StatusFlags::from_bits_truncate(self.status.read())
|
||||
}
|
||||
|
||||
fn wait_write(&mut self) {
|
||||
while self.status().contains(StatusFlags::INPUT_FULL) {}
|
||||
fn wait_write(&mut self) -> Result<(), Error> {
|
||||
let mut timeout = 100;
|
||||
while self.status().contains(StatusFlags::INPUT_FULL) && timeout > 0 {
|
||||
thread::sleep(time::Duration::from_millis(1));
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::WriteTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_read(&mut self) {
|
||||
while ! self.status().contains(StatusFlags::OUTPUT_FULL) {}
|
||||
fn wait_read(&mut self) -> Result<(), Error> {
|
||||
let mut timeout = 100;
|
||||
while ! self.status().contains(StatusFlags::OUTPUT_FULL) && timeout > 0 {
|
||||
thread::sleep(time::Duration::from_millis(1));
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::ReadTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_read(&mut self, message: &str) {
|
||||
@@ -108,84 +134,86 @@ impl Ps2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn command(&mut self, command: Command) {
|
||||
self.wait_write();
|
||||
fn command(&mut self, command: Command) -> Result<(), Error> {
|
||||
self.wait_write()?;
|
||||
self.command.write(command as u8);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self) -> u8 {
|
||||
self.wait_read();
|
||||
self.data.read()
|
||||
fn read(&mut self) -> Result<u8, Error> {
|
||||
self.wait_read()?;
|
||||
Ok(self.data.read())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: u8) {
|
||||
self.wait_write();
|
||||
fn write(&mut self, data: u8) -> Result<(), Error> {
|
||||
self.wait_write()?;
|
||||
self.data.write(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn config(&mut self) -> ConfigFlags {
|
||||
self.command(Command::ReadConfig);
|
||||
ConfigFlags::from_bits_truncate(self.read())
|
||||
fn config(&mut self) -> Result<ConfigFlags, Error> {
|
||||
self.command(Command::ReadConfig)?;
|
||||
self.read().map(ConfigFlags::from_bits_truncate)
|
||||
}
|
||||
|
||||
fn set_config(&mut self, config: ConfigFlags) {
|
||||
self.command(Command::WriteConfig);
|
||||
self.write(config.bits());
|
||||
fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> {
|
||||
self.command(Command::WriteConfig)?;
|
||||
self.write(config.bits())
|
||||
}
|
||||
|
||||
fn keyboard_command_inner(&mut self, command: u8) -> u8 {
|
||||
fn keyboard_command_inner(&mut self, command: u8) -> Result<u8, Error> {
|
||||
let mut ret = 0xFE;
|
||||
for i in 0..4 {
|
||||
self.write(command as u8);
|
||||
ret = self.read();
|
||||
self.write(command as u8)?;
|
||||
ret = self.read()?;
|
||||
if ret == 0xFE {
|
||||
println!("ps2d: retry keyboard command {:X}: {}", command, i);
|
||||
eprintln!("ps2d: retry keyboard command {:X}: {}", command, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 {
|
||||
fn keyboard_command(&mut self, command: KeyboardCommand) -> Result<u8, Error> {
|
||||
self.keyboard_command_inner(command as u8)
|
||||
}
|
||||
|
||||
fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 {
|
||||
let res = self.keyboard_command_inner(command as u8);
|
||||
fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> Result<u8, Error> {
|
||||
let res = self.keyboard_command_inner(command as u8)?;
|
||||
if res != 0xFA {
|
||||
return res;
|
||||
return Ok(res);
|
||||
}
|
||||
self.write(data as u8);
|
||||
self.read()
|
||||
}
|
||||
|
||||
fn mouse_command_inner(&mut self, command: u8) -> u8 {
|
||||
fn mouse_command_inner(&mut self, command: u8) -> Result<u8, Error> {
|
||||
let mut ret = 0xFE;
|
||||
for i in 0..4 {
|
||||
self.command(Command::WriteSecond);
|
||||
self.write(command as u8);
|
||||
ret = self.read();
|
||||
self.command(Command::WriteSecond)?;
|
||||
self.write(command as u8)?;
|
||||
ret = self.read()?;
|
||||
if ret == 0xFE {
|
||||
println!("ps2d: retry mouse command {:X}: {}", command, i);
|
||||
eprintln!("ps2d: retry mouse command {:X}: {}", command, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn mouse_command(&mut self, command: MouseCommand) -> u8 {
|
||||
fn mouse_command(&mut self, command: MouseCommand) -> Result<u8, Error> {
|
||||
self.mouse_command_inner(command as u8)
|
||||
}
|
||||
|
||||
fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 {
|
||||
let res = self.mouse_command_inner(command as u8);
|
||||
fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result<u8, Error> {
|
||||
let res = self.mouse_command_inner(command as u8)?;
|
||||
if res != 0xFA {
|
||||
return res;
|
||||
return Ok(res);
|
||||
}
|
||||
self.command(Command::WriteSecond);
|
||||
self.write(data as u8);
|
||||
self.command(Command::WriteSecond)?;
|
||||
self.write(data as u8)?;
|
||||
self.read()
|
||||
}
|
||||
|
||||
@@ -199,50 +227,50 @@ impl Ps2 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> bool {
|
||||
pub fn init(&mut self) -> Result<(), Error> {
|
||||
let mut b = 0;
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("init start");
|
||||
|
||||
// Disable devices
|
||||
self.command(Command::DisableFirst);
|
||||
self.command(Command::DisableSecond);
|
||||
self.command(Command::DisableFirst)?;
|
||||
self.command(Command::DisableSecond)?;
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("disable");
|
||||
|
||||
// Disable clocks, disable interrupts, and disable translate
|
||||
{
|
||||
let mut config = self.config();
|
||||
let mut config = self.config()?;
|
||||
config.insert(ConfigFlags::FIRST_DISABLED);
|
||||
config.insert(ConfigFlags::SECOND_DISABLED);
|
||||
config.remove(ConfigFlags::FIRST_TRANSLATE);
|
||||
config.remove(ConfigFlags::FIRST_INTERRUPT);
|
||||
config.remove(ConfigFlags::SECOND_INTERRUPT);
|
||||
self.set_config(config);
|
||||
self.set_config(config)?;
|
||||
}
|
||||
|
||||
// Perform the self test
|
||||
self.command(Command::TestController);
|
||||
assert_eq!(self.read(), 0x55);
|
||||
self.command(Command::TestController)?;
|
||||
assert_eq!(self.read()?, 0x55);
|
||||
|
||||
// Enable devices
|
||||
self.command(Command::EnableFirst);
|
||||
self.command(Command::EnableSecond);
|
||||
self.command(Command::EnableFirst)?;
|
||||
self.command(Command::EnableSecond)?;
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("enable");
|
||||
|
||||
// Reset keyboard
|
||||
b = self.keyboard_command(KeyboardCommand::Reset);
|
||||
b = self.keyboard_command(KeyboardCommand::Reset)?;
|
||||
if b == 0xFA {
|
||||
b = self.read();
|
||||
b = self.read()?;
|
||||
if b != 0xAA {
|
||||
println!("ps2d: keyboard failed self test: {:02X}", b);
|
||||
eprintln!("ps2d: keyboard failed self test: {:02X}", b);
|
||||
}
|
||||
} else {
|
||||
println!("ps2d: keyboard failed to reset: {:02X}", b);
|
||||
eprintln!("ps2d: keyboard failed to reset: {:02X}", b);
|
||||
}
|
||||
|
||||
// Clear remaining data
|
||||
@@ -250,31 +278,43 @@ impl Ps2 {
|
||||
|
||||
// Set scancode set to 2
|
||||
let scancode_set = 2;
|
||||
b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set);
|
||||
b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?;
|
||||
if b != 0xFA {
|
||||
println!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b);
|
||||
eprintln!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b);
|
||||
}
|
||||
|
||||
// Enable data reporting
|
||||
b = self.keyboard_command(KeyboardCommand::EnableReporting);
|
||||
b = self.keyboard_command(KeyboardCommand::EnableReporting)?;
|
||||
if b != 0xFA {
|
||||
println!("ps2d: keyboard failed to enable reporting: {:02X}", b);
|
||||
eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b);
|
||||
}
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("init finish");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_mouse(&mut self) -> Result<bool, Error> {
|
||||
let mut b = 0;
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("mouse init start");
|
||||
|
||||
// Reset mouse and set up scroll
|
||||
b = self.mouse_command(MouseCommand::Reset);
|
||||
b = self.mouse_command(MouseCommand::Reset)?;
|
||||
if b == 0xFA {
|
||||
b = self.read();
|
||||
b = self.read()?;
|
||||
if b != 0xAA {
|
||||
println!("ps2d: mouse failed self test 1: {:02X}", b);
|
||||
eprintln!("ps2d: mouse failed self test 1: {:02X}", b);
|
||||
}
|
||||
|
||||
b = self.read();
|
||||
b = self.read()?;
|
||||
if b != 0x00 {
|
||||
println!("ps2d: mouse failed self test 2: {:02X}", b);
|
||||
eprintln!("ps2d: mouse failed self test 2: {:02X}", b);
|
||||
}
|
||||
} else {
|
||||
println!("ps2d: mouse failed to reset: {:02X}", b);
|
||||
eprintln!("ps2d: mouse failed to reset: {:02X}", b);
|
||||
}
|
||||
|
||||
// Clear remaining data
|
||||
@@ -282,47 +322,47 @@ impl Ps2 {
|
||||
|
||||
// Enable extra packet on mouse
|
||||
//TODO: show error return values
|
||||
if self.mouse_command_data(MouseCommandData::SetSampleRate, 200) != 0xFA
|
||||
|| self.mouse_command_data(MouseCommandData::SetSampleRate, 100) != 0xFA
|
||||
|| self.mouse_command_data(MouseCommandData::SetSampleRate, 80) != 0xFA {
|
||||
println!("ps2d: mouse failed to enable extra packet");
|
||||
if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA
|
||||
|| self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA
|
||||
|| self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA {
|
||||
eprintln!("ps2d: mouse failed to enable extra packet");
|
||||
}
|
||||
|
||||
b = self.mouse_command(MouseCommand::GetDeviceId);
|
||||
b = self.mouse_command(MouseCommand::GetDeviceId)?;
|
||||
let mouse_extra = if b == 0xFA {
|
||||
self.read() == 3
|
||||
self.read()? == 3
|
||||
} else {
|
||||
println!("ps2d: mouse failed to get device id: {:02X}", b);
|
||||
eprintln!("ps2d: mouse failed to get device id: {:02X}", b);
|
||||
false
|
||||
};
|
||||
|
||||
// Set sample rate to maximum
|
||||
let sample_rate = 200;
|
||||
b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate);
|
||||
b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?;
|
||||
if b != 0xFA {
|
||||
println!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b);
|
||||
eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b);
|
||||
}
|
||||
|
||||
// Enable data reporting
|
||||
b = self.mouse_command(MouseCommand::EnableReporting);
|
||||
b = self.mouse_command(MouseCommand::EnableReporting)?;
|
||||
if b != 0xFA {
|
||||
println!("ps2d: mouse failed to enable reporting: {:02X}", b);
|
||||
eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b);
|
||||
}
|
||||
|
||||
// Enable clocks and interrupts
|
||||
{
|
||||
let mut config = self.config();
|
||||
let mut config = self.config()?;
|
||||
config.remove(ConfigFlags::FIRST_DISABLED);
|
||||
config.remove(ConfigFlags::SECOND_DISABLED);
|
||||
config.insert(ConfigFlags::FIRST_TRANSLATE);
|
||||
config.insert(ConfigFlags::FIRST_INTERRUPT);
|
||||
config.insert(ConfigFlags::SECOND_INTERRUPT);
|
||||
self.set_config(config);
|
||||
self.set_config(config)?;
|
||||
}
|
||||
|
||||
// Clear remaining data
|
||||
self.flush_read("init finish");
|
||||
self.flush_read("mouse init finish");
|
||||
|
||||
mouse_extra
|
||||
Ok(mouse_extra)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-16
@@ -12,7 +12,6 @@ use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use syscall::call::iopl;
|
||||
use syscall::flag::CloneFlags;
|
||||
|
||||
use crate::state::Ps2d;
|
||||
|
||||
@@ -21,7 +20,7 @@ mod keymap;
|
||||
mod state;
|
||||
mod vm;
|
||||
|
||||
fn daemon(input: File) {
|
||||
fn daemon(daemon: syscall::Daemon) -> ! {
|
||||
unsafe {
|
||||
iopl(3).expect("ps2d: failed to get I/O permission");
|
||||
}
|
||||
@@ -39,6 +38,11 @@ fn daemon(input: File) {
|
||||
None => (keymap::us::get_char)
|
||||
};
|
||||
|
||||
let input = OpenOptions::new()
|
||||
.write(true)
|
||||
.open("display:input")
|
||||
.expect("p2sd: failed to open display:input");
|
||||
|
||||
let mut event_file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
@@ -71,10 +75,12 @@ fn daemon(input: File) {
|
||||
data: 1
|
||||
}).expect("ps2d: failed to event irq:12");
|
||||
|
||||
let mut ps2d = Ps2d::new(input, keymap);
|
||||
|
||||
syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace");
|
||||
|
||||
daemon.ready().expect("p2sd: failed to mark daemon as ready");
|
||||
|
||||
let mut ps2d = Ps2d::new(input, keymap);
|
||||
|
||||
let mut data = [0; 256];
|
||||
loop {
|
||||
// There are some gotchas with ps/2 controllers that require this weird
|
||||
@@ -108,19 +114,10 @@ fn daemon(input: File) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match OpenOptions::new().write(true).open("display:input") {
|
||||
Ok(input) => {
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 {
|
||||
daemon(input);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
println!("ps2d: failed to open display: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
syscall::Daemon::new(daemon).expect("p2sd: failed to create daemon");
|
||||
}
|
||||
|
||||
+11
-4
@@ -45,7 +45,14 @@ pub struct Ps2d<F: Fn(u8,bool) -> char> {
|
||||
impl<F: Fn(u8,bool) -> char> Ps2d<F> {
|
||||
pub fn new(input: File, keymap: F) -> Self {
|
||||
let mut ps2 = Ps2::new();
|
||||
let extra_packet = ps2.init();
|
||||
ps2.init().expect("ps2d: failed to initialize");
|
||||
let extra_packet = match ps2.init_mouse() {
|
||||
Ok(ok) => ok,
|
||||
Err(err) => {
|
||||
eprintln!("p2sd: failed to initialize mouse: {:?}", err);
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let vmmouse_relative = true;
|
||||
let vmmouse = false; //vm::enable(vmmouse_relative);
|
||||
@@ -121,7 +128,7 @@ impl<F: Fn(u8,bool) -> char> Ps2d<F> {
|
||||
}
|
||||
|
||||
if queue_length % 4 != 0 {
|
||||
println!("ps2d: queue length not a multiple of 4: {}", queue_length);
|
||||
eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -177,7 +184,7 @@ impl<F: Fn(u8,bool) -> char> Ps2d<F> {
|
||||
|
||||
let flags = MousePacketFlags::from_bits_truncate(self.packets[0]);
|
||||
if ! flags.contains(MousePacketFlags::ALWAYS_ON) {
|
||||
println!("ps2d: mouse misalign {:X}", self.packets[0]);
|
||||
eprintln!("ps2d: mouse misalign {:X}", self.packets[0]);
|
||||
|
||||
self.packets = [0; 4];
|
||||
self.packet_i = 0;
|
||||
@@ -230,7 +237,7 @@ impl<F: Fn(u8,bool) -> char> Ps2d<F> {
|
||||
}.to_event()).expect("ps2d: failed to write button event");
|
||||
}
|
||||
} else {
|
||||
println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]);
|
||||
eprintln!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]);
|
||||
}
|
||||
|
||||
self.packets = [0; 4];
|
||||
|
||||
+3
-3
@@ -57,20 +57,20 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) {
|
||||
}
|
||||
|
||||
pub fn enable(relative: bool) -> bool {
|
||||
println!("ps2d: Enable vmmouse");
|
||||
eprintln!("ps2d: Enable vmmouse");
|
||||
|
||||
unsafe {
|
||||
let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE);
|
||||
|
||||
let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0);
|
||||
if (status & 0x0000ffff) == 0 {
|
||||
println!("ps2d: No vmmouse");
|
||||
eprintln!("ps2d: No vmmouse");
|
||||
return false;
|
||||
}
|
||||
|
||||
let (version, _, _, _, _, _) = cmd(ABSPOINTER_DATA, 1);
|
||||
if version != VERSION {
|
||||
println!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION);
|
||||
eprintln!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION);
|
||||
let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user