From 0ff0c42ce6b4640079708034313b58c0804d8597 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 20:34:13 -0700 Subject: [PATCH] p2sd: Add timeout handling --- ps2d/Cargo.toml | 2 +- ps2d/src/controller.rs | 192 +++++++++++++++++++++++++---------------- ps2d/src/main.rs | 29 +++---- ps2d/src/state.rs | 15 +++- ps2d/src/vm.rs | 6 +- 5 files changed, 144 insertions(+), 100 deletions(-) diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 27e3b5e582..fa34ed3874 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.2.9" +redox_syscall = "0.2.11" diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index a10660010a..3cf5ede5c1 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -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 { + 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 { + 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 { 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 { 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 { + 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 { 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 { 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 { + 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 { + 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) } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 58dd4d38b2..56bd0a2014 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -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"); } diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 6671dc7ed8..38bb484457 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -45,7 +45,14 @@ pub struct Ps2d char> { impl char> Ps2d { 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 char> Ps2d { } 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 char> Ps2d { 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 char> Ps2d { }.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]; diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index be4b0ab443..b067a8f41e 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -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; }