Skip to content

Commit 6f8da8f

Browse files
Merge pull request #90 from FrameworkComputer/touchscreen
touchscreen: Dump firmware version and protocol
2 parents 84a79f9 + 2ddf762 commit 6f8da8f

File tree

8 files changed

+314
-4
lines changed

8 files changed

+314
-4
lines changed

README.md

+27-3
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ see the [Support Matrices](support-matrices.md).
4040
- [x] Get firmware version from system (`--versions`)
4141
- [x] BIOS
4242
- [x] EC
43-
- [x] PD
43+
- [x] PD Controller
4444
- [x] ME (Only on Linux)
4545
- [x] Retimer
46-
- [x] Touchpad (Linux and Windows)
46+
- [x] Touchpad (Linux, Windows, FreeBSD, not UEFI)
47+
- [x] Touchscreen (Linux, Windows, FreeBSD, not UEFI)
4748
- [x] Get Expansion Card Firmware (Not on UEFI so far)
4849
- [x] HDMI Expansion Card (`--dp-hdmi-info`)
4950
- [x] DisplayPort Expansion Card (`--dp-hdmi-info`)
@@ -68,7 +69,9 @@ All of these need EC communication support in order to work.
6869

6970
- [x] Get and set keyboard brightness (`--kblight`)
7071
- [x] Get and set battery charge limit (`--charge-limit`)
71-
- [x] Get and set fingerprint LED brightness (`--fp-brightness`)
72+
- [x] Get and set fingerprint LED brightness (`--fp-brightness`, `--fp-led-level`)
73+
- [x] Override tablet mode, instead of follow G-Sensor and hall sensor (`--tablet-mode`)
74+
- [x] Disable/Enable touchscreen (`--touchscreen-enable`)
7275

7376
###### Communication with Embedded Controller
7477

@@ -176,9 +179,30 @@ Options:
176179
--h2o-capsule <H2O_CAPSULE> Parse UEFI Capsule information from binary file
177180
--intrusion Show status of intrusion switch
178181
--inputmodules Show status of the input modules (Framework 16 only)
182+
--input-deck-mode <INPUT_DECK_MODE>
183+
Set input deck power mode [possible values: auto, off, on] (Framework 16 only) [possible values: auto, off, on]
184+
--charge-limit [<CHARGE_LIMIT>]
185+
Get or set max charge limit
186+
--get-gpio <GET_GPIO>
187+
Get GPIO value by name
188+
--fp-led-level [<FP_LED_LEVEL>]
189+
Get or set fingerprint LED brightness level [possible values: high, medium, low, ultra-low, auto]
190+
--fp-brightness [<FP_BRIGHTNESS>]
191+
Get or set fingerprint LED brightness percentage
179192
--kblight [<KBLIGHT>] Set keyboard backlight percentage or get, if no value provided
193+
--tablet-mode <TABLET_MODE> Set tablet mode override [possible values: auto, tablet, laptop]
194+
--touchscreen-enable <TOUCHSCREEN_ENABLE>
195+
Enable/disable touchscreen [possible values: true, false]
180196
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
197+
--reboot-ec <REBOOT_EC> Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump]
198+
--hash <HASH> Hash a file of arbitrary data
181199
--driver <DRIVER> Select which driver is used. By default portio is used [possible values: portio, cros-ec, windows]
200+
--pd-addrs <PD_ADDRS> <PD_ADDRS>
201+
Specify I2C addresses of the PD chips (Advanced)
202+
--pd-ports <PD_PORTS> <PD_PORTS>
203+
Specify I2C ports of the PD chips (Advanced)
204+
--has-mec <HAS_MEC>
205+
Specify the type of EC chip (MEC/MCHP or other) [possible values: true, false]
182206
-t, --test Run self-test to check if interaction with EC is possible
183207
-h, --help Print help information
184208
```

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/commandline/clap_std.rs

+6
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ struct ClapCli {
162162
#[arg(long)]
163163
tablet_mode: Option<TabletModeArg>,
164164

165+
/// Enable/disable touchscreen
166+
#[clap(value_enum)]
167+
#[arg(long)]
168+
touchscreen_enable: Option<bool>,
169+
165170
/// Get EC console, choose whether recent or to follow the output
166171
#[clap(value_enum)]
167172
#[arg(long)]
@@ -284,6 +289,7 @@ pub fn parse(args: &[String]) -> Cli {
284289
kblight: args.kblight,
285290
rgbkbd: args.rgbkbd,
286291
tablet_mode: args.tablet_mode,
292+
touchscreen_enable: args.touchscreen_enable,
287293
console: args.console,
288294
reboot_ec: args.reboot_ec,
289295
hash: args.hash.map(|x| x.into_os_string().into_string().unwrap()),

framework_lib/src/commandline/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ use crate::smbios::ConfigDigit0;
5252
use crate::smbios::{dmidecode_string_val, get_smbios, is_framework};
5353
#[cfg(feature = "hidapi")]
5454
use crate::touchpad::print_touchpad_fw_ver;
55+
#[cfg(any(feature = "hidapi", feature = "windows"))]
56+
use crate::touchscreen;
5557
#[cfg(feature = "uefi")]
5658
use crate::uefi::enable_page_break;
5759
use crate::util;
@@ -173,6 +175,7 @@ pub struct Cli {
173175
pub kblight: Option<Option<u8>>,
174176
pub rgbkbd: Vec<u64>,
175177
pub tablet_mode: Option<TabletModeArg>,
178+
pub touchscreen_enable: Option<bool>,
176179
pub console: Option<ConsoleArg>,
177180
pub reboot_ec: Option<RebootEcArg>,
178181
pub hash: Option<String>,
@@ -479,6 +482,9 @@ fn print_versions(ec: &CrosEc) {
479482

480483
#[cfg(feature = "hidapi")]
481484
let _ignore_err = print_touchpad_fw_ver();
485+
486+
#[cfg(feature = "hidapi")]
487+
let _ignore_err = touchscreen::print_fw_ver();
482488
}
483489

484490
fn print_esrt() {
@@ -793,6 +799,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
793799
TabletModeArg::Laptop => TabletModeOverride::ForceClamshell,
794800
};
795801
ec.set_tablet_mode(mode);
802+
} else if let Some(_enable) = &args.touchscreen_enable {
803+
#[cfg(any(feature = "hidapi", feature = "windows"))]
804+
if touchscreen::enable_touch(*_enable).is_none() {
805+
error!("Failed to enable/disable touch");
806+
}
796807
} else if let Some(console_arg) = &args.console {
797808
match console_arg {
798809
ConsoleArg::Follow => {

framework_lib/src/commandline/uefi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub fn parse(args: &[String]) -> Cli {
8989
kblight: None,
9090
rgbkbd: vec![],
9191
tablet_mode: None,
92+
touchscreen_enable: None,
9293
console: None,
9394
reboot_ec: None,
9495
hash: None,

framework_lib/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ pub mod audio_card;
1818
pub mod camera;
1919
#[cfg(feature = "hidapi")]
2020
pub mod touchpad;
21+
#[cfg(any(feature = "hidapi", feature = "windows"))]
22+
pub mod touchscreen;
23+
#[cfg(feature = "windows")]
24+
pub mod touchscreen_win;
2125

2226
#[cfg(feature = "uefi")]
2327
#[macro_use]

framework_lib/src/touchscreen.rs

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use hidapi::{HidApi, HidDevice};
2+
3+
#[cfg(target_os = "windows")]
4+
use crate::touchscreen_win;
5+
6+
pub const ILI_VID: u16 = 0x222A;
7+
pub const ILI_PID: u16 = 0x5539;
8+
pub const USI_BITMAP: u8 = 1 << 1;
9+
pub const MPP_BITMAP: u8 = 1 << 2;
10+
11+
struct HidapiTouchScreen {
12+
device: HidDevice,
13+
}
14+
15+
impl TouchScreen for HidapiTouchScreen {
16+
fn open_device() -> Option<HidapiTouchScreen> {
17+
debug!("Looking for touchscreen HID device");
18+
match HidApi::new() {
19+
Ok(api) => {
20+
for dev_info in api.device_list() {
21+
let vid = dev_info.vendor_id();
22+
let pid = dev_info.product_id();
23+
let usage_page = dev_info.usage_page();
24+
if vid != ILI_VID {
25+
trace!(" Skipping VID:PID. Expected {:04X}:*", ILI_VID);
26+
continue;
27+
}
28+
debug!(
29+
" Found {:04X}:{:04X} (Usage Page {:04X})",
30+
vid, pid, usage_page
31+
);
32+
if usage_page != 0xFF00 {
33+
debug!(" Skipping usage page. Expected {:04X}", 0xFF00);
34+
continue;
35+
}
36+
if pid != ILI_PID {
37+
debug!(" Warning: PID is {:04X}, expected {:04X}", pid, ILI_PID);
38+
}
39+
40+
debug!(" Found matching touchscreen HID device");
41+
debug!(" Path: {:?}", dev_info.path());
42+
debug!(" IC Type: {:04X}", pid);
43+
44+
// Unwrapping because if we can enumerate it, we should be able to open it
45+
let device = dev_info.open_device(&api).unwrap();
46+
debug!(" Opened device.");
47+
48+
return Some(HidapiTouchScreen { device });
49+
}
50+
}
51+
Err(e) => {
52+
error!("Failed to open hidapi. Error: {e}");
53+
}
54+
};
55+
56+
None
57+
}
58+
59+
fn send_message(&self, message_id: u8, read_len: usize, data: Vec<u8>) -> Option<Vec<u8>> {
60+
let report_id = 0x03;
61+
let data_len = data.len();
62+
let mut msg = [0u8; 0x40];
63+
msg[0] = report_id;
64+
msg[1] = 0xA3;
65+
msg[2] = data_len as u8;
66+
msg[3] = read_len as u8;
67+
msg[4] = message_id;
68+
for (i, b) in data.into_iter().enumerate() {
69+
msg[5 + i] = b;
70+
}
71+
72+
// Not sure why, but on Windows we just have to write an output report
73+
// HidApiError { message: "HidD_SetFeature: (0x00000057) The parameter is incorrect." }
74+
// Still doesn't work on Windows. Need to write a byte more than the buffer is long
75+
#[cfg(target_os = "windows")]
76+
let send_feature_report = false;
77+
#[cfg(not(target_os = "windows"))]
78+
let send_feature_report = true;
79+
80+
if send_feature_report {
81+
debug!(" send_feature_report {:X?}", msg);
82+
self.device.send_feature_report(&msg).ok()?;
83+
} else {
84+
debug!(" Writing {:X?}", msg);
85+
self.device.write(&msg).ok()?;
86+
};
87+
88+
if read_len == 0 {
89+
return Some(vec![]);
90+
}
91+
92+
let msg_len = 3 + data_len;
93+
let mut buf: [u8; 0x40] = [0; 0x40];
94+
debug!(" Reading");
95+
let res = self.device.read(&mut buf);
96+
debug!(" res: {:?}", res);
97+
debug!(" Read buf: {:X?}", buf);
98+
Some(buf[msg_len..msg_len + read_len].to_vec())
99+
}
100+
}
101+
102+
pub trait TouchScreen {
103+
fn open_device() -> Option<Self>
104+
where
105+
Self: std::marker::Sized;
106+
fn send_message(&self, message_id: u8, read_len: usize, data: Vec<u8>) -> Option<Vec<u8>>;
107+
108+
fn check_fw_version(&self) -> Option<()> {
109+
println!("Touchscreen");
110+
let res = self.send_message(0x42, 3, vec![0])?;
111+
let ver = res
112+
.iter()
113+
.skip(1)
114+
.fold(format!("{:02X}", res[0]), |acc, &x| {
115+
acc + "." + &format!("{:02X}", x)
116+
});
117+
// Expecting 06.00.0A
118+
debug!(" Protocol Version: v{}", ver);
119+
120+
let res = self.send_message(0x40, 8, vec![0])?;
121+
let ver = res
122+
.iter()
123+
.skip(1)
124+
.fold(res[0].to_string(), |acc, &x| acc + "." + &x.to_string());
125+
println!(" Firmware Version: v{}", ver);
126+
127+
let res = self.send_message(0x20, 16, vec![0])?;
128+
println!(" USI Protocol: {:?}", (res[15] & USI_BITMAP) > 0);
129+
println!(" MPP Protocol: {:?}", (res[15] & MPP_BITMAP) > 0);
130+
131+
Some(())
132+
}
133+
134+
fn enable_touch(&self, enable: bool) -> Option<()> {
135+
self.send_message(0x38, 0, vec![!enable as u8, 0x00])?;
136+
Some(())
137+
}
138+
}
139+
140+
pub fn print_fw_ver() -> Option<()> {
141+
#[cfg(target_os = "windows")]
142+
let device = touchscreen_win::NativeWinTouchScreen::open_device()?;
143+
#[cfg(not(target_os = "windows"))]
144+
let device = HidapiTouchScreen::open_device()?;
145+
146+
device.check_fw_version()
147+
}
148+
149+
pub fn enable_touch(enable: bool) -> Option<()> {
150+
#[cfg(target_os = "windows")]
151+
let device = touchscreen_win::NativeWinTouchScreen::open_device()?;
152+
#[cfg(not(target_os = "windows"))]
153+
let device = HidapiTouchScreen::open_device()?;
154+
155+
device.enable_touch(enable)
156+
}

0 commit comments

Comments
 (0)