PS2 mouse refactor

This commit is contained in:
Jeremy Soller
2026-01-25 10:07:58 -07:00
parent 10dd00f0cb
commit 511d446993
5 changed files with 481 additions and 250 deletions
+23 -162
View File
@@ -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<F: Fn(&mut Self) -> Result<u8, Error>>(
fn retry<T, F: Fn(&mut Self) -> Result<T, Error>>(
&mut self,
name: fmt::Arguments,
retries: usize,
f: F,
) -> Result<u8, Error> {
trace!("ps2d: {}", name);
) -> Result<T, Error> {
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<u8, Error> {
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<u8, Error> {
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<u8, Error> {
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<bool, Error> {
{
// 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<bool, Error> {
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(())
}
}
+22 -1
View File
@@ -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 {
+261
View File
@@ -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)
}
}
}
}
+171 -83
View File
@@ -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<TimeSpec>,
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<u8>) {
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;
}
}
}
+4 -4
View File
@@ -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);