ps2d: add MouseTx abstraction and WIP touchpad identification
This commit is contained in:
+159
-48
@@ -21,9 +21,56 @@ enum MouseCommand {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(u8)]
|
||||
enum MouseCommandData {
|
||||
SetResolution = 0xE8,
|
||||
SetSampleRate = 0xF3,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MouseTx {
|
||||
write: &'static [u8],
|
||||
write_i: usize,
|
||||
read: Vec<u8>,
|
||||
read_bytes: usize,
|
||||
}
|
||||
|
||||
impl MouseTx {
|
||||
fn new(write: &'static [u8], read_bytes: usize, ps2: &mut Ps2) -> Result<Self, ()> {
|
||||
let mut this = Self {
|
||||
write,
|
||||
write_i: 0,
|
||||
read: Vec::with_capacity(read_bytes),
|
||||
read_bytes,
|
||||
};
|
||||
this.try_write(ps2)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn try_write(&mut self, ps2: &mut Ps2) -> Result<(), ()> {
|
||||
if let Some(write) = self.write.get(self.write_i) {
|
||||
if let Err(err) = ps2.mouse_command_async(*write) {
|
||||
log::error!("failed to write {:02X} to mouse: {:?}", write, err);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle(&mut self, data: u8, ps2: &mut Ps2) -> Result<bool, ()> {
|
||||
if self.write_i < self.write.len() {
|
||||
if data == 0xFA {
|
||||
self.write_i += 1;
|
||||
self.try_write(ps2)?;
|
||||
} else {
|
||||
log::error!("unknown mouse response {:02X}", data);
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
self.read.push(data);
|
||||
}
|
||||
Ok(self.write_i >= self.write.len() && self.read.len() >= self.read_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
@@ -47,8 +94,12 @@ pub enum MouseState {
|
||||
Reset,
|
||||
/// BAT completion code returned
|
||||
Bat,
|
||||
/// Identify touchpad
|
||||
IdentifyTouchpad { tx: MouseTx },
|
||||
/// Enable intellimouse features
|
||||
EnableIntellimouse { index: usize, sent_command: bool },
|
||||
EnableIntellimouse { tx: MouseTx },
|
||||
/// Status request
|
||||
Status { index: usize },
|
||||
/// Device ID update
|
||||
DeviceId,
|
||||
/// Enable reporting command sent
|
||||
@@ -96,6 +147,20 @@ impl MouseState {
|
||||
}
|
||||
}
|
||||
|
||||
fn request_status(&mut self, ps2: &mut Ps2) -> MouseResult {
|
||||
match ps2.mouse_command_async(MouseCommand::StatusRequest as u8) {
|
||||
Ok(()) => {
|
||||
*self = MouseState::Status { index: 0 };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to request mouse status: {:?}", err);
|
||||
//TODO: reset mouse instead?
|
||||
self.request_id(ps2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn request_id(&mut self, ps2: &mut Ps2) -> MouseResult {
|
||||
match ps2.mouse_command_async(MouseCommand::GetDeviceId as u8) {
|
||||
Ok(()) => {
|
||||
@@ -110,40 +175,45 @@ impl MouseState {
|
||||
}
|
||||
}
|
||||
|
||||
fn identify_touchpad(&mut self, ps2: &mut Ps2) -> MouseResult {
|
||||
let cmd = TouchpadCommand::Identify as u8;
|
||||
match MouseTx::new(&[
|
||||
// Ensure command alignment
|
||||
MouseCommand::SetScaling1To1 as u8,
|
||||
// Send special identify touchpad command
|
||||
MouseCommandData::SetResolution as u8, 0,
|
||||
MouseCommandData::SetResolution as u8, 0,
|
||||
MouseCommandData::SetResolution as u8, 0,
|
||||
MouseCommandData::SetResolution as u8, 0,
|
||||
// Status request
|
||||
MouseCommand::StatusRequest as u8
|
||||
], 3, ps2) {
|
||||
Ok(tx) => {
|
||||
*self = MouseState::IdentifyTouchpad { tx };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
},
|
||||
Err(()) => {
|
||||
self.enable_intellimouse(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)
|
||||
}
|
||||
match MouseTx::new(&[
|
||||
MouseCommandData::SetSampleRate as u8, 200,
|
||||
MouseCommandData::SetSampleRate as u8, 100,
|
||||
MouseCommandData::SetSampleRate as u8, 80
|
||||
], 0, ps2) {
|
||||
Ok(tx) => {
|
||||
*self = MouseState::EnableIntellimouse { tx };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
},
|
||||
Err(()) => {
|
||||
self.request_id(ps2)
|
||||
}
|
||||
} else {
|
||||
self.request_id(ps2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +244,7 @@ impl MouseState {
|
||||
if data == MouseId::Base as u8 {
|
||||
// Enable intellimouse features
|
||||
log::debug!("BAT mouse id {:02X} (base)", data);
|
||||
self.enable_intellimouse(0, false, ps2)
|
||||
self.identify_touchpad(ps2)
|
||||
} else if data == MouseId::Intellimouse1 as u8 {
|
||||
// Extra packet already enabled
|
||||
log::debug!("BAT mouse id {:02X} (intellimouse)", data);
|
||||
@@ -184,18 +254,50 @@ impl MouseState {
|
||||
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::IdentifyTouchpad { ref mut tx } => {
|
||||
match tx.handle(data, ps2) {
|
||||
Ok(done) => if done {
|
||||
//TODO: handle touchpad identification
|
||||
// If tx.read[1] == 0x47, this is a synaptics touchpad
|
||||
self.request_status(ps2)
|
||||
} else {
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
},
|
||||
Err(()) => {
|
||||
self.enable_intellimouse(ps2)
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseState::EnableIntellimouse { ref mut tx } => {
|
||||
match tx.handle(data, ps2) {
|
||||
Ok(done) => if done {
|
||||
self.request_status(ps2)
|
||||
} else {
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
},
|
||||
Err(()) => {
|
||||
self.request_status(ps2)
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseState::Status { index } => {
|
||||
match index {
|
||||
0 => {
|
||||
//TODO: check response
|
||||
*self = MouseState::Status { index: 1 };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
}
|
||||
1 => {
|
||||
*self = MouseState::Status { index: 2 };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
}
|
||||
2 => {
|
||||
*self = MouseState::Status { index: 3 };
|
||||
MouseResult::Timeout(COMMAND_TIMEOUT)
|
||||
}
|
||||
_ => {
|
||||
self.request_id(ps2)
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseState::DeviceId => {
|
||||
@@ -232,27 +334,36 @@ impl MouseState {
|
||||
self.reset(ps2)
|
||||
}
|
||||
MouseState::Reset => {
|
||||
log::warn!("timeout while waiting for mouse reset");
|
||||
log::warn!("timeout waiting for mouse reset");
|
||||
//TODO: retry reset?
|
||||
*self = MouseState::None;
|
||||
MouseResult::None
|
||||
}
|
||||
MouseState::Bat => {
|
||||
log::warn!("timeout while waiting for BAT completion");
|
||||
log::warn!("timeout waiting for BAT completion");
|
||||
//TODO: limit number of resets
|
||||
self.reset(ps2)
|
||||
}
|
||||
MouseState::IdentifyTouchpad { .. } => {
|
||||
//TODO: retry?
|
||||
log::warn!("timeout identifying touchpad");
|
||||
self.request_status(ps2)
|
||||
}
|
||||
MouseState::EnableIntellimouse { .. } => {
|
||||
//TODO: retry?
|
||||
log::warn!("timeout while enabling intellimouse");
|
||||
log::warn!("timeout enabling intellimouse");
|
||||
self.request_status(ps2)
|
||||
}
|
||||
MouseState::Status { index } => {
|
||||
log::warn!("timeout waiting for mouse status {}", index);
|
||||
self.request_id(ps2)
|
||||
}
|
||||
MouseState::DeviceId => {
|
||||
log::warn!("timeout while requesting mouse id");
|
||||
log::warn!("timeout requesting mouse id");
|
||||
self.enable_reporting(0, ps2)
|
||||
}
|
||||
MouseState::EnableReporting { id } => {
|
||||
log::warn!("timeout while enabling reporting");
|
||||
log::warn!("timeout enabling reporting");
|
||||
//TODO: limit number of retries
|
||||
self.enable_reporting(id, ps2)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user