Skip to content

Commit f62df30

Browse files
committed
touchscreen: Make it work on windows
``` > target\debug\framework_tool.exe --versions Firmware Version: v7.0.0.4.0.0.0.0 USI Protocol: false MPP Protocol: true ``` Signed-off-by: Daniel Schaefer <[email protected]>
1 parent ccf498a commit f62df30

File tree

4 files changed

+161
-23
lines changed

4 files changed

+161
-23
lines changed

framework_lib/Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ uefi = { version = "0.20", features = ["alloc"], optional = true }
6363
uefi-services = { version = "0.17", optional = true }
6464
plain = { version = "0.2.3", optional = true }
6565
spin = { version = "0.9.8", optional = false }
66-
hidapi = { version = "2.6.3", optional = true }
66+
hidapi = { version = "2.6.3", optional = true, features = [ "windows-native" ] }
6767
rusb = { version = "0.9.4", optional = true }
6868
no-std-compat = { version = "0.4.1", features = [ "alloc" ] }
6969
guid_macros = { path = "../guid_macros" }
@@ -89,5 +89,12 @@ features = [
8989
"Win32_System_IO",
9090
"Win32_System_Ioctl",
9191
"Win32_System_SystemServices",
92+
# For HID devices
93+
"Win32_Devices_DeviceAndDriverInstallation",
94+
"Win32_Devices_HumanInterfaceDevice",
95+
"Win32_Devices_Properties",
96+
"Win32_Storage_EnhancedStorage",
97+
"Win32_System_Threading",
98+
"Win32_UI_Shell_PropertiesSystem"
9299
]
93100

framework_lib/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub mod camera;
2020
pub mod touchpad;
2121
#[cfg(feature = "hidapi")]
2222
pub mod touchscreen;
23+
#[cfg(feature = "windows")]
24+
pub mod touchscreen_win;
2325

2426
#[cfg(feature = "uefi")]
2527
#[macro_use]

framework_lib/src/touchscreen.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use hidapi::{HidApi, HidDevice, HidError};
22

3+
#[cfg(target_os = "windows")]
4+
use crate::touchscreen_win;
5+
6+
use std::{thread, time};
7+
38
pub const ILI_VID: u16 = 0x222A;
49
pub const ILI_PID: u16 = 0x5539;
510
pub const USI_BITMAP: u8 = 1 << 1;
@@ -20,6 +25,7 @@ fn send_message(device: &HidDevice, message_id: u8, read_len: usize, data: Vec<u
2025

2126
// Not sure why, but on Windows we just have to write an output report
2227
// HidApiError { message: "HidD_SetFeature: (0x00000057) The parameter is incorrect." }
28+
// Still doesn't work on Windows. Need to write a byte more than the buffer is long
2329
#[cfg(target_os = "windows")]
2430
let send_feature_report = false;
2531
#[cfg(not(target_os = "windows"))]
@@ -33,7 +39,6 @@ fn send_message(device: &HidDevice, message_id: u8, read_len: usize, data: Vec<u
3339
device.write(&msg)?;
3440
}
3541

36-
use std::{thread, time};
3742
thread::sleep(time::Duration::from_millis(1000));
3843

3944
if read_len == 0 {
@@ -46,28 +51,10 @@ fn send_message(device: &HidDevice, message_id: u8, read_len: usize, data: Vec<u
4651
let mut res = device.read(&mut buf);
4752
debug!(" res: {:?}", res);
4853
debug!(" Read buf: {:X?}", buf);
49-
if let Err(_) = res {
50-
res = device.read_timeout(&mut buf[..read_len + msg_len], 100);
51-
debug!(" res: {:?}", res);
52-
debug!(" Read buf: {:X?}", buf);
53-
}
54-
if let Err(_) = res {
55-
res = device.read_timeout(&mut buf[..read_len + msg_len], 100);
56-
debug!(" res: {:?}", res);
57-
debug!(" Read buf: {:X?}", buf);
58-
}
59-
if let Err(_) = res {
60-
res = device.read_timeout(&mut buf[..read_len + msg_len], 100);
61-
debug!(" res: {:?}", res);
62-
debug!(" Read buf: {:X?}", buf);
63-
}
64-
if let Err(_) = res {
65-
device.read_timeout(&mut buf[..read_len + msg_len], 100)?;
66-
debug!(" Read buf: {:X?}", buf);
67-
}
6854
Ok(buf[msg_len..msg_len + read_len].to_vec())
6955
}
7056

57+
#[cfg(not(target_os = "windows"))]
7158
fn check_fw_version(device: &HidDevice) -> Result<(), HidError> {
7259
device.set_blocking_mode(true).unwrap();
7360
send_message(device, 0xF0, 0, vec![3, 0, 0]).unwrap();
@@ -97,7 +84,13 @@ fn check_fw_version(device: &HidDevice) -> Result<(), HidError> {
9784
Ok(())
9885
}
9986

100-
pub fn print_touchscreen_fw_ver() -> Result<(), HidError> {
87+
#[cfg(target_os = "windows")]
88+
pub fn print_touchscreen_fw_ver() -> Option<()> {
89+
touchscreen_win::print_touchscreen_fw_ver()
90+
}
91+
92+
#[cfg(not(target_os = "windows"))]
93+
pub fn print_touchscreen_fw_ver() -> Option<()> {
10194
debug!("Looking for touchscreen HID device");
10295
match HidApi::new() {
10396
Ok(api) => {
@@ -141,5 +134,5 @@ pub fn print_touchscreen_fw_ver() -> Result<(), HidError> {
141134
}
142135
};
143136

144-
Ok(())
137+
Some(())
145138
}

framework_lib/src/touchscreen_win.rs

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#[allow(unused_imports)]
2+
use windows::{
3+
core::*,
4+
Win32::{
5+
Devices::HumanInterfaceDevice::*,
6+
Devices::Properties::*,
7+
Foundation::*,
8+
Storage::FileSystem::*,
9+
System::{Ioctl::*, IO::*},
10+
System::Threading::ResetEvent,
11+
System::IO::{CancelIoEx, DeviceIoControl},
12+
},
13+
};
14+
15+
pub const USI_BITMAP: u8 = 1 << 1;
16+
pub const MPP_BITMAP: u8 = 1 << 2;
17+
18+
pub fn open_device(open_rw: bool) -> Option<HANDLE> {
19+
// TODO: I don't know if this might be different on other systems
20+
// Should enumerate and find the right one
21+
// See: https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/finding-and-opening-a-hid-collection
22+
let path = w!(r"\\?\HID#ILIT2901&Col03#5&357cbf85&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}");
23+
24+
let res = unsafe {
25+
CreateFileW(
26+
path,
27+
match open_rw {
28+
true => FILE_GENERIC_WRITE.0 | FILE_GENERIC_READ.0,
29+
false => 0,
30+
},
31+
FILE_SHARE_READ | FILE_SHARE_WRITE,
32+
None,
33+
OPEN_EXISTING,
34+
// hidapi-rs is using FILE_FLAG_OVERLAPPED but it doesn't look like we need that
35+
FILE_FLAGS_AND_ATTRIBUTES(0),
36+
None,
37+
)
38+
};
39+
let handle = match res {
40+
Ok(h) => h,
41+
Err(err) => {
42+
error!("Failed to open device {:?}", err);
43+
return None;
44+
}
45+
};
46+
47+
debug!("Opened {:?}", path);
48+
49+
Some(handle)
50+
}
51+
52+
pub fn send_message(handle: &HANDLE, message_id: u8, read_len: usize, data: Vec<u8>) -> Option<Vec<u8>> {
53+
let report_id = 0x03;
54+
let data_len = data.len();
55+
let mut msg = [0u8; 0x40];
56+
let msg_len = 3 + data_len;
57+
msg[0] = report_id;
58+
msg[1] = 0xA3;
59+
msg[2] = data_len as u8;
60+
msg[3] = read_len as u8;
61+
msg[4] = message_id;
62+
for (i, b) in data.into_iter().enumerate() {
63+
msg[5 + i] = b;
64+
}
65+
66+
let mut buf = [0u8; 0x40];
67+
buf[0] = report_id;
68+
69+
unsafe {
70+
debug!(" HidD_SetOutputReport {:X?}", msg);
71+
let success = HidD_SetOutputReport(
72+
*handle,
73+
// Microsoft docs says that the first byte of the message has to be the report ID.
74+
// This is normal with HID implementations.
75+
// But it seems on Windows (at least for this device's firmware) we have to set the
76+
// length as one more than the buffer is long.
77+
// Otherwise no data is returned in the read call later.
78+
msg.as_mut_ptr() as _,
79+
msg.len() as u32 + 1,
80+
);
81+
debug!(" Success: {}", success);
82+
83+
let mut bytes_read = 0;
84+
debug!(" ReadFile");
85+
// HidD_GetFeature doesn't work, have to use ReadFile
86+
// Microsoft does recommend that
87+
// https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/obtaining-hid-reports
88+
let res = ReadFile(
89+
*handle,
90+
Some(&mut buf),
91+
Some(&mut bytes_read),
92+
None,
93+
);
94+
debug!(" Success: {:?}, Bytes: {}", res, bytes_read);
95+
debug!(" Read buf: {:X?}", buf);
96+
debug!(" Read msg: {:X?}", msg);
97+
98+
}
99+
100+
Some(buf[msg_len..msg_len + read_len].to_vec())
101+
}
102+
103+
pub fn check_fw_version(device: &HANDLE) -> Option<()> {
104+
let res = send_message(device, 0x42, 3, vec![0])?;
105+
let ver = res
106+
.iter()
107+
.skip(1)
108+
.fold(format!("{:02X}", res[0]), |acc, &x| {
109+
acc + "." + &format!("{:02X}", x)
110+
});
111+
// Expecting 06.00.0A
112+
debug!(" Protocol Version: v{}", ver);
113+
114+
let res = send_message(device, 0x40, 8, vec![0])?;
115+
let ver = res
116+
.iter()
117+
.skip(1)
118+
.fold(res[0].to_string(), |acc, &x| acc + "." + &x.to_string());
119+
println!(" Firmware Version: v{}", ver);
120+
121+
let res = send_message(device, 0x20, 16, vec![0])?;
122+
println!(" USI Protocol: {:?}", (res[15] & USI_BITMAP) > 0);
123+
println!(" MPP Protocol: {:?}", (res[15] & MPP_BITMAP) > 0);
124+
125+
Some(())
126+
}
127+
128+
pub fn print_touchscreen_fw_ver() -> Option<()> {
129+
let device = open_device(true)?;
130+
131+
if let None = check_fw_version(&device) {
132+
error!("Failed to read touchscreen firmware version");
133+
};
134+
135+
Some(())
136+
}

0 commit comments

Comments
 (0)