From 511d446993e2e77546f633ea3b32a9176d63ad0b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 25 Jan 2026 10:07:58 -0700 Subject: [PATCH] PS2 mouse refactor --- drivers/input/ps2d/src/controller.rs | 185 +++---------------- drivers/input/ps2d/src/main.rs | 23 ++- drivers/input/ps2d/src/mouse.rs | 261 +++++++++++++++++++++++++++ drivers/input/ps2d/src/state.rs | 254 +++++++++++++++++--------- drivers/input/ps2d/src/vm.rs | 8 +- 5 files changed, 481 insertions(+), 250 deletions(-) create mode 100644 drivers/input/ps2d/src/mouse.rs diff --git a/drivers/input/ps2d/src/controller.rs b/drivers/input/ps2d/src/controller.rs index 5d71bbad9f..b3c0ce0e0f 100644 --- a/drivers/input/ps2d/src/controller.rs +++ b/drivers/input/ps2d/src/controller.rs @@ -13,7 +13,7 @@ use common::io::Pio; #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] use common::io::Mmio; -use log::{debug, error, trace, warn}; +use log::{debug, error, info, trace, warn}; use std::fmt; @@ -25,8 +25,6 @@ pub enum Error { WriteTimeout, CommandTimeout(Command), WriteConfigTimeout(ConfigFlags), - MouseCommandFail(MouseCommand), - MouseCommandDataFail(MouseCommandData), KeyboardCommandFail(KeyboardCommand), KeyboardCommandDataFail(KeyboardCommandData), } @@ -94,30 +92,10 @@ enum KeyboardCommandData { ScancodeSet = 0xF0, } -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -#[allow(dead_code)] -enum MouseCommand { - SetScaling1To1 = 0xE6, - SetScaling2To1 = 0xE7, - StatusRequest = 0xE9, - GetDeviceId = 0xF2, - EnableReporting = 0xF4, - SetDefaultsDisable = 0xF5, - SetDefaults = 0xF6, - Reset = 0xFF, -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -enum MouseCommandData { - SetSampleRate = 0xF3, -} - // Default timeout in microseconds const DEFAULT_TIMEOUT: u64 = 50_000; // Reset timeout in microseconds -const RESET_TIMEOUT: u64 = 500_000; +const RESET_TIMEOUT: u64 = 1_000_000; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub struct Ps2 { @@ -195,13 +173,13 @@ impl Ps2 { Ok(()) } - fn retry Result>( + fn retry Result>( &mut self, name: fmt::Arguments, retries: usize, f: F, - ) -> Result { - trace!("ps2d: {}", name); + ) -> Result { + trace!("{}", name); let mut res = Err(Error::NoMoreTries); for retry in 0..retries { res = f(self); @@ -210,7 +188,7 @@ impl Ps2 { return Ok(ok); } Err(ref err) => { - debug!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); + debug!("{}: retry {}/{}: {:?}", name, retry + 1, retries, err); } } } @@ -263,7 +241,7 @@ impl Ps2 { .keyboard_command_inner(command as u8) .map_err(|_| Error::KeyboardCommandDataFail(command))?; if res != 0xFA { - warn!("ps2d: keyboard incorrect result of set command: {command:?} {res:02X}"); + warn!("keyboard incorrect result of set command: {command:?} {res:02X}"); return Ok(res); } x.write(data); @@ -272,39 +250,9 @@ impl Ps2 { ) } - fn mouse_command_inner(&mut self, command: u8) -> Result { + pub fn mouse_command_async(&mut self, command: u8) -> Result<(), Error> { self.command(Command::WriteSecond)?; - self.write(command as u8)?; - match self.read()? { - 0xFE => Err(Error::CommandRetry), - value => Ok(value), - } - } - - fn mouse_command(&mut self, command: MouseCommand) -> Result { - self.retry(format_args!("mouse command {:?}", command), 4, |x| { - x.mouse_command_inner(command as u8) - .map_err(|_| Error::MouseCommandFail(command)) - }) - } - - fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result { - self.retry( - format_args!("mouse command {:?} {:#x}", command, data), - 4, - |x| { - let res = x - .mouse_command_inner(command as u8) - .map_err(|_| Error::MouseCommandDataFail(command))?; - if res != 0xFA { - warn!("ps2d: mouse incorrect result of set command: {command:?} {res:02X}"); - return Ok(res); - } - x.command(Command::WriteSecond)?; - x.write(data as u8)?; - x.read() - }, - ) + self.write(command as u8) } pub fn next(&mut self) -> Option<(bool, u8)> { @@ -331,10 +279,10 @@ impl Ps2 { if b == 0xFA { b = self.read().unwrap_or(0); if b != 0xAA { - error!("ps2d: keyboard failed self test: {:02X}", b); + error!("keyboard failed self test: {:02X}", b); } } else { - error!("ps2d: keyboard failed to reset: {:02X}", b); + error!("keyboard failed to reset: {:02X}", b); } } @@ -342,7 +290,7 @@ impl Ps2 { // Set defaults and disable scanning let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; if b != 0xFA { - error!("ps2d: keyboard failed to set defaults: {:02X}", b); + error!("keyboard failed to set defaults: {:02X}", b); return Err(Error::CommandRetry); } @@ -355,7 +303,7 @@ impl Ps2 { b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; if b != 0xFA { error!( - "ps2d: keyboard failed to set scancode set {}: {:02X}", + "keyboard failed to set scancode set {}: {:02X}", scancode_set, b ); } @@ -364,86 +312,7 @@ impl Ps2 { Ok(()) } - pub fn init_mouse(&mut self) -> Result { - { - // Enable second device - self.command(Command::EnableSecond)?; - } - - self.retry(format_args!("mouse reset"), 4, |x| { - // Reset mouse - let mut b = x.mouse_command(MouseCommand::Reset)?; - if b == 0xFA { - b = x.read_timeout(RESET_TIMEOUT)?; - if b != 0xAA { - error!("ps2d: mouse failed self test 1: {:02X}", b); - return Err(Error::CommandRetry); - } - - b = x.read_timeout(RESET_TIMEOUT)?; - if b != 0x00 { - error!("ps2d: mouse failed self test 2: {:02X}", b); - return Err(Error::CommandRetry); - } - } else { - error!("ps2d: mouse failed to reset: {:02X}", b); - return Err(Error::CommandRetry); - } - - Ok(b) - })?; - - { - // 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 - { - error!("ps2d: mouse failed to enable extra packet"); - } - } - - let b = self.mouse_command(MouseCommand::GetDeviceId)?; - let mouse_extra = if b == 0xFA { - self.read()? == 3 - } else { - error!("ps2d: mouse failed to get device id: {:02X}", b); - false - }; - - { - // Set sample rate to maximum - let sample_rate = 200; - let b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; - if b != 0xFA { - error!( - "ps2d: mouse failed to set sample rate to {}: {:02X}", - sample_rate, b - ); - } - } - - { - let b = self.mouse_command(MouseCommand::StatusRequest)?; - if b != 0xFA { - error!("ps2d: mouse failed to request status: {:02X}", b); - } else { - let a = self.read()?; - let b = self.read()?; - let c = self.read()?; - - debug!( - "ps2d: mouse status {:#x} resolution {} sample rate {}", - a, b, c - ); - } - } - - Ok(mouse_extra) - } - - pub fn init(&mut self) -> Result { + pub fn init(&mut self) -> Result<(), Error> { { // Disable devices self.command(Command::DisableFirst)?; @@ -465,22 +334,22 @@ impl Ps2 { self.command(Command::TestController)?; let r = self.read()?; if r != 0x55 { - warn!("ps2d: self test unexpected value: {:02X}", r); + warn!("self test unexpected value: {:02X}", r); } } // Initialize keyboard if let Err(err) = self.init_keyboard() { - error!("ps2d: failed to initialize keyboard: {:?}", err); + error!("failed to initialize keyboard: {:?}", err); return Err(err); } - // Initialize mouse - let (mouse_found, mouse_extra) = match self.init_mouse() { - Ok(ok) => (true, ok), + // Enable second device + let enable_mouse = match self.command(Command::EnableSecond) { + Ok(()) => true, Err(err) => { - error!("ps2d: failed to initialize mouse: {:?}", err); - (false, false) + error!("failed to initialize mouse: {:?}", err); + false } }; @@ -492,20 +361,12 @@ impl Ps2 { //TODO: fix by using interrupts? } - if mouse_found { - // Enable mouse data reporting - // Use inner function to prevent retries - self.mouse_command_inner(MouseCommand::EnableReporting as u8)?; - // Response is ignored since scanning is now on - //TODO: fix by using interrupts? - } - // Enable clocks and interrupts { let config = ConfigFlags::POST_PASSED | ConfigFlags::FIRST_INTERRUPT | ConfigFlags::FIRST_TRANSLATE - | if mouse_found { + | if enable_mouse { ConfigFlags::SECOND_INTERRUPT } else { ConfigFlags::SECOND_DISABLED @@ -513,6 +374,6 @@ impl Ps2 { self.set_config(config)?; } - Ok(mouse_extra) + Ok(()) } } diff --git a/drivers/input/ps2d/src/main.rs b/drivers/input/ps2d/src/main.rs index db87bc55fa..92fd065a82 100644 --- a/drivers/input/ps2d/src/main.rs +++ b/drivers/input/ps2d/src/main.rs @@ -19,6 +19,7 @@ use syscall::{EAGAIN, EWOULDBLOCK}; use crate::state::Ps2d; mod controller; +mod mouse; mod state; mod vm; @@ -39,6 +40,7 @@ fn daemon(daemon: daemon::Daemon) -> ! { enum Source { Keyboard, Mouse, + Time, } } @@ -75,11 +77,26 @@ fn daemon(daemon: daemon::Daemon) -> ! { ) .unwrap(); + let mut time_file = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(syscall::O_NONBLOCK as i32) + .open(format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC)) + .expect("ps2d: failed to open /scheme/time"); + + event_queue + .subscribe( + time_file.as_raw_fd() as usize, + Source::Time, + event::EventFlags::READ, + ) + .unwrap(); + libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); daemon.ready(); - let mut ps2d = Ps2d::new(input); + let mut ps2d = Ps2d::new(input, time_file); let mut data = [0; 256]; for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) { @@ -95,6 +112,10 @@ fn daemon(daemon: daemon::Daemon) -> ! { let (file, keyboard) = match event { Source::Keyboard => (&mut key_file, true), Source::Mouse => (&mut mouse_file, false), + Source::Time => { + ps2d.time_event(); + continue; + } }; loop { diff --git a/drivers/input/ps2d/src/mouse.rs b/drivers/input/ps2d/src/mouse.rs new file mode 100644 index 0000000000..6b3c4095b3 --- /dev/null +++ b/drivers/input/ps2d/src/mouse.rs @@ -0,0 +1,261 @@ +use crate::controller::Ps2; +use std::time::Duration; + +pub const RESET_TIMEOUT: Duration = Duration::from_millis(1000); +pub const COMMAND_TIMEOUT: Duration = Duration::from_millis(100); + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +#[allow(dead_code)] +enum MouseCommand { + SetScaling1To1 = 0xE6, + SetScaling2To1 = 0xE7, + StatusRequest = 0xE9, + GetDeviceId = 0xF2, + EnableReporting = 0xF4, + SetDefaultsDisable = 0xF5, + SetDefaults = 0xF6, + Reset = 0xFF, +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +enum MouseCommandData { + SetSampleRate = 0xF3, +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +#[allow(dead_code)] +enum MouseId { + /// Mouse sends three bytes + Base = 0x00, + /// Mouse sends fourth byte with scroll + Intellimouse1 = 0x03, + /// Mouse sends fourth byte with scroll, button 4, and button 5 + //TODO: support this mouse type + Intellimouse2 = 0x04, +} + +#[derive(Debug)] +pub enum MouseState { + /// No mouse found + None, + /// Ready to initialize mouse + Init, + /// Reset command is sent + Reset, + /// BAT completion code returned + Bat, + /// Enable intellimouse features + EnableIntellimouse { index: usize, sent_command: bool }, + /// Device ID update + DeviceId, + /// Enable reporting command sent + EnableReporting { id: u8 }, + /// Mouse is streaming + Streaming { id: u8 }, +} + +#[derive(Debug)] +#[must_use] +pub enum MouseResult { + None, + Packet(u8, bool), + Timeout(Duration), +} + +impl MouseState { + pub fn reset(&mut self, ps2: &mut Ps2) -> MouseResult { + match ps2.mouse_command_async(MouseCommand::Reset as u8) { + Ok(()) => { + *self = MouseState::Reset; + MouseResult::Timeout(RESET_TIMEOUT) + } + Err(err) => { + log::error!("failed to send mouse reset command: {:?}", err); + //TODO: retry reset? + *self = MouseState::None; + MouseResult::None + } + } + } + + fn enable_reporting(&mut self, id: u8, ps2: &mut Ps2) -> MouseResult { + match ps2.mouse_command_async(MouseCommand::EnableReporting as u8) { + Ok(()) => { + *self = MouseState::EnableReporting { id }; + MouseResult::Timeout(COMMAND_TIMEOUT) + } + Err(err) => { + log::error!("failed to enable mouse reporting: {:?}", err); + //TODO: reset mouse? + *self = MouseState::None; + MouseResult::None + } + } + } + + fn request_id(&mut self, ps2: &mut Ps2) -> MouseResult { + match ps2.mouse_command_async(MouseCommand::GetDeviceId as u8) { + Ok(()) => { + *self = MouseState::DeviceId; + MouseResult::Timeout(COMMAND_TIMEOUT) + } + Err(err) => { + log::error!("failed to request mouse id: {:?}", err); + //TODO: reset mouse instead? + self.enable_reporting(MouseId::Base as u8, ps2) + } + } + } + + fn enable_intellimouse( + &mut self, + index: usize, + sent_command: bool, + ps2: &mut Ps2, + ) -> MouseResult { + let magic = [200, 100, 80]; + if let Some(data) = magic.get(index) { + match ps2.mouse_command_async(if sent_command { + *data + } else { + MouseCommandData::SetSampleRate as u8 + }) { + Ok(()) => { + *self = if sent_command { + MouseState::EnableIntellimouse { + index: index + 1, + sent_command: false, + } + } else { + MouseState::EnableIntellimouse { + index, + sent_command: true, + } + }; + MouseResult::Timeout(COMMAND_TIMEOUT) + } + Err(err) => { + log::error!("failed to send intellimouse command: {:?}", err); + self.request_id(ps2) + } + } + } else { + self.request_id(ps2) + } + } + + pub fn handle(&mut self, data: u8, ps2: &mut Ps2) -> MouseResult { + match *self { + MouseState::None | MouseState::Init => { + //TODO: enable port in this case, mouse hotplug may send 0xAA 0x00 + log::error!( + "received mouse byte {:02X} when mouse not initialized", + data + ); + MouseResult::None + } + MouseState::Reset => { + if data == 0xFA { + log::debug!("mouse reset ok"); + MouseResult::Timeout(RESET_TIMEOUT) + } else if data == 0xAA { + log::debug!("BAT completed"); + *self = MouseState::Bat; + MouseResult::Timeout(COMMAND_TIMEOUT) + } else { + log::warn!("unknown mouse response {:02X} after reset", data); + self.reset(ps2) + } + } + MouseState::Bat => { + if data == MouseId::Base as u8 { + // Enable intellimouse features + log::debug!("BAT mouse id {:02X} (base)", data); + self.enable_intellimouse(0, false, ps2) + } else if data == MouseId::Intellimouse1 as u8 { + // Extra packet already enabled + log::debug!("BAT mouse id {:02X} (intellimouse)", data); + self.enable_reporting(data, ps2) + } else { + log::warn!("unknown mouse id {:02X} after BAT", data); + MouseResult::Timeout(RESET_TIMEOUT) + } + } + MouseState::EnableIntellimouse { + index, + sent_command, + } => { + if data == 0xFA { + self.enable_intellimouse(index, sent_command, ps2) + } else { + log::warn!( + "unknown mouse response {:02X} while enabling intellimouse", + data + ); + self.request_id(ps2) + } + } + MouseState::DeviceId => { + if data == 0xFA { + // Command OK response + //TODO: handle this separately? + MouseResult::Timeout(COMMAND_TIMEOUT) + } else if data == MouseId::Base as u8 || data == MouseId::Intellimouse1 as u8 { + log::debug!("mouse id {:02X}", data); + self.enable_reporting(data, ps2) + } else { + log::warn!("unknown mouse id {:02X} after requesting id", data); + self.reset(ps2) + } + } + MouseState::EnableReporting { id } => { + log::debug!("mouse id {:02X} enable reporting {:02X}", id, data); + //TODO: handle response ok/error + *self = MouseState::Streaming { id }; + MouseResult::None + } + MouseState::Streaming { id } => { + MouseResult::Packet(data, id == MouseId::Intellimouse1 as u8) + } + } + } + + pub fn handle_timeout(&mut self, ps2: &mut Ps2) -> MouseResult { + let mut res = MouseResult::None; + match *self { + MouseState::None | MouseState::Streaming { .. } => MouseResult::None, + MouseState::Init => { + // The state uses a timeout on init to request a reset + self.reset(ps2) + } + MouseState::Reset => { + log::warn!("timeout while waiting for mouse reset"); + //TODO: retry reset? + *self = MouseState::None; + MouseResult::None + } + MouseState::Bat => { + log::warn!("timeout while waiting for BAT completion"); + //TODO: limit number of resets + self.reset(ps2) + } + MouseState::EnableIntellimouse { .. } => { + //TODO: retry? + log::warn!("timeout while enabling intellimouse"); + self.request_id(ps2) + } + MouseState::DeviceId => { + log::warn!("timeout while requesting mouse id"); + self.enable_reporting(0, ps2) + } + MouseState::EnableReporting { id } => { + log::warn!("timeout while enabling reporting"); + //TODO: limit number of retries + self.enable_reporting(id, ps2) + } + } + } +} diff --git a/drivers/input/ps2d/src/state.rs b/drivers/input/ps2d/src/state.rs index f876a36317..98533b2156 100644 --- a/drivers/input/ps2d/src/state.rs +++ b/drivers/input/ps2d/src/state.rs @@ -1,8 +1,16 @@ use inputd::ProducerHandle; -use log::{error, warn}; +use log::{error, info, warn}; use orbclient::{ButtonEvent, KeyEvent, MouseEvent, MouseRelativeEvent, ScrollEvent}; +use std::{ + convert::TryInto, + fs::File, + io::{Read, Write}, + time::Duration, +}; +use syscall::TimeSpec; use crate::controller::Ps2; +use crate::mouse::{MouseResult, MouseState}; use crate::vm; bitflags! { @@ -18,46 +26,69 @@ bitflags! { } } +fn timespec_from_duration(duration: Duration) -> TimeSpec { + TimeSpec { + tv_sec: duration.as_secs().try_into().unwrap(), + tv_nsec: duration.subsec_nanos().try_into().unwrap(), + } +} + +fn duration_from_timespec(timespec: TimeSpec) -> Duration { + Duration::new( + timespec.tv_sec.try_into().unwrap(), + timespec.tv_nsec.try_into().unwrap(), + ) +} + pub struct Ps2d { ps2: Ps2, vmmouse: bool, vmmouse_relative: bool, input: ProducerHandle, + time_file: File, extended: bool, mouse_x: i32, mouse_y: i32, mouse_left: bool, mouse_middle: bool, mouse_right: bool, + mouse_state: MouseState, + mouse_timeout: Option, packets: [u8; 4], packet_i: usize, - extra_packet: bool, } impl Ps2d { - pub fn new(input: ProducerHandle) -> Self { + pub fn new(input: ProducerHandle, time_file: File) -> Self { let mut ps2 = Ps2::new(); - let extra_packet = ps2.init().expect("ps2d: failed to initialize"); + ps2.init().expect("failed to initialize"); // FIXME add an option for orbital to disable this when an app captures the mouse. let vmmouse_relative = false; let vmmouse = vm::enable(vmmouse_relative); - Ps2d { + let mut this = Ps2d { ps2, vmmouse, vmmouse_relative, input, + time_file, extended: false, mouse_x: 0, mouse_y: 0, mouse_left: false, mouse_middle: false, mouse_right: false, + mouse_state: MouseState::Init, + mouse_timeout: None, packets: [0; 4], packet_i: 0, - extra_packet, - } + }; + + // This triggers initializing the mouse + this.handle_mouse(None); + + this } pub fn irq(&mut self) { @@ -66,6 +97,24 @@ impl Ps2d { } } + pub fn time_event(&mut self) { + let mut time = TimeSpec::default(); + match self.time_file.read(&mut time) { + Ok(_count) => {} + Err(err) => { + log::error!("failed to read time file: {}", err); + return; + } + } + if let Some(mouse_timeout) = self.mouse_timeout { + if time.tv_sec > mouse_timeout.tv_sec + || (time.tv_sec == mouse_timeout.tv_sec && time.tv_nsec >= mouse_timeout.tv_nsec) + { + self.handle_mouse(None); + } + } + } + pub fn handle(&mut self, keyboard: bool, data: u8) { if keyboard { if data == 0xE0 { @@ -109,7 +158,7 @@ impl Ps2d { /* 0x80 to 0xFF used for press/release detection */ _ => { if pressed { - warn!("ps2d: unknown extended scancode {:02X}", ps2_scancode); + warn!("unknown extended scancode {:02X}", ps2_scancode); } 0 } @@ -208,7 +257,7 @@ impl Ps2d { /* 0x80 to 0xFF used for press/release detection */ _ => { if pressed { - warn!("ps2d: unknown scancode {:02X}", ps2_scancode); + warn!("unknown scancode {:02X}", ps2_scancode); } 0 } @@ -225,7 +274,7 @@ impl Ps2d { } .to_event(), ) - .expect("ps2d: failed to write key event"); + .expect("failed to write key event"); } } } else if self.vmmouse { @@ -239,7 +288,7 @@ impl Ps2d { } if queue_length % 4 != 0 { - error!("ps2d: queue length not a multiple of 4: {}", queue_length); + error!("queue length not a multiple of 4: {}", queue_length); break; } @@ -304,83 +353,122 @@ impl Ps2d { } } } else { - self.packets[self.packet_i] = data; - self.packet_i += 1; + self.handle_mouse(Some(data)); + } + } - let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if !flags.contains(MousePacketFlags::ALWAYS_ON) { - error!("ps2d: mouse misalign {:X}", self.packets[0]); - - self.packets = [0; 4]; - self.packet_i = 0; - } else if self.packet_i >= self.packets.len() - || (!self.extra_packet && self.packet_i >= 3) - { - if !flags.contains(MousePacketFlags::X_OVERFLOW) - && !flags.contains(MousePacketFlags::Y_OVERFLOW) - { - let mut dx = self.packets[1] as i32; - if flags.contains(MousePacketFlags::X_SIGN) { - dx -= 0x100; + pub fn handle_mouse(&mut self, data_opt: Option) { + let mouse_res = match data_opt { + Some(data) => self.mouse_state.handle(data, &mut self.ps2), + None => self.mouse_state.handle_timeout(&mut self.ps2), + }; + self.mouse_timeout = None; + let (packet_data, extra_packet) = match mouse_res { + MouseResult::None => { + return; + } + MouseResult::Packet(packet_data, extra_packet) => (packet_data, extra_packet), + MouseResult::Timeout(duration) => { + // Read current time + let mut time = TimeSpec::default(); + match self.time_file.read(&mut time) { + Ok(_count) => {} + Err(err) => { + log::error!("failed to read time file: {}", err); + return; } - - let mut dy = -(self.packets[2] as i32); - if flags.contains(MousePacketFlags::Y_SIGN) { - dy += 0x100; - } - - let mut dz = 0; - if self.extra_packet { - let mut scroll = (self.packets[3] & 0xF) as i8; - if scroll & (1 << 3) == 1 << 3 { - scroll -= 16; - } - dz = -scroll as i32; - } - - if dx != 0 || dy != 0 { - self.input - .write_event(MouseRelativeEvent { dx, dy }.to_event()) - .expect("ps2d: failed to write mouse event"); - } - - if dz != 0 { - self.input - .write_event(ScrollEvent { x: 0, y: dz }.to_event()) - .expect("ps2d: failed to write scroll event"); - } - - let left = flags.contains(MousePacketFlags::LEFT_BUTTON); - let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON); - let right = flags.contains(MousePacketFlags::RIGHT_BUTTON); - if left != self.mouse_left - || middle != self.mouse_middle - || right != self.mouse_right - { - self.mouse_left = left; - self.mouse_middle = middle; - self.mouse_right = right; - self.input - .write_event( - ButtonEvent { - left, - middle, - right, - } - .to_event(), - ) - .expect("ps2d: failed to write button event"); - } - } else { - warn!( - "ps2d: overflow {:X} {:X} {:X} {:X}", - self.packets[0], self.packets[1], self.packets[2], self.packets[3] - ); } - self.packets = [0; 4]; - self.packet_i = 0; + // Add duration to time + time = timespec_from_duration(duration_from_timespec(time) + duration); + + // Write next time + match self.time_file.write(&time) { + Ok(_count) => {} + Err(err) => { + log::error!("failed to write time file: {}", err); + } + } + + self.mouse_timeout = Some(time); + return; } + }; + + self.packets[self.packet_i] = packet_data; + self.packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); + if !flags.contains(MousePacketFlags::ALWAYS_ON) { + error!("mouse misalign {:X}", self.packets[0]); + + self.packets = [0; 4]; + self.packet_i = 0; + } else if self.packet_i >= self.packets.len() || (!extra_packet && self.packet_i >= 3) { + if !flags.contains(MousePacketFlags::X_OVERFLOW) + && !flags.contains(MousePacketFlags::Y_OVERFLOW) + { + let mut dx = self.packets[1] as i32; + if flags.contains(MousePacketFlags::X_SIGN) { + dx -= 0x100; + } + + let mut dy = -(self.packets[2] as i32); + if flags.contains(MousePacketFlags::Y_SIGN) { + dy += 0x100; + } + + let mut dz = 0; + if extra_packet { + let mut scroll = (self.packets[3] & 0xF) as i8; + if scroll & (1 << 3) == 1 << 3 { + scroll -= 16; + } + dz = -scroll as i32; + } + + if dx != 0 || dy != 0 { + self.input + .write_event(MouseRelativeEvent { dx, dy }.to_event()) + .expect("ps2d: failed to write mouse event"); + } + + if dz != 0 { + self.input + .write_event(ScrollEvent { x: 0, y: dz }.to_event()) + .expect("ps2d: failed to write scroll event"); + } + + let left = flags.contains(MousePacketFlags::LEFT_BUTTON); + let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON); + let right = flags.contains(MousePacketFlags::RIGHT_BUTTON); + if left != self.mouse_left + || middle != self.mouse_middle + || right != self.mouse_right + { + self.mouse_left = left; + self.mouse_middle = middle; + self.mouse_right = right; + self.input + .write_event( + ButtonEvent { + left, + middle, + right, + } + .to_event(), + ) + .expect("ps2d: failed to write button event"); + } + } else { + warn!( + "overflow {:X} {:X} {:X} {:X}", + self.packets[0], self.packets[1], self.packets[2], self.packets[3] + ); + } + + self.packets = [0; 4]; + self.packet_i = 0; } } } diff --git a/drivers/input/ps2d/src/vm.rs b/drivers/input/ps2d/src/vm.rs index aea6c7ad9d..71b7141704 100644 --- a/drivers/input/ps2d/src/vm.rs +++ b/drivers/input/ps2d/src/vm.rs @@ -69,12 +69,12 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { } pub fn enable(relative: bool) -> bool { - trace!("ps2d: Enable vmmouse"); + trace!("Enable vmmouse"); unsafe { let (eax, ebx, _, _) = cmd(GETVERSION, 0); if ebx != MAGIC || eax == 0xFFFFFFFF { - info!("ps2d: No vmmouse support"); + info!("No vmmouse support"); return false; } @@ -82,14 +82,14 @@ pub fn enable(relative: bool) -> bool { let (status, _, _, _) = cmd(ABSPOINTER_STATUS, 0); if (status & 0x0000ffff) == 0 { - info!("ps2d: No vmmouse"); + info!("No vmmouse"); return false; } let (version, _, _, _) = cmd(ABSPOINTER_DATA, 1); if version != VERSION { error!( - "ps2d: Invalid vmmouse version: {} instead of {}", + "Invalid vmmouse version: {} instead of {}", version, VERSION ); let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE);